Removed Birthday Code and ...
Removed Birthday Code and added better error reporting and logging.
This commit is contained in:
1 parent
7a7288a5bf
commit
d874ddeb7e
52 files changed
+12489
-5832
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,147 @@
|
||||
package com.github.joelgodofwar.mmh.common;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.github.joelgodofwar.mmh.common.error.BasicErrorReporter;
|
||||
import com.github.joelgodofwar.mmh.common.error.ErrorReporter;
|
||||
import com.github.joelgodofwar.mmh.common.error.ReportType;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
public class PluginLibrary {
|
||||
|
||||
/**
|
||||
* The minimum version MoreMobHeads has been tested with.
|
||||
*/
|
||||
public static final String MINIMUM_MINECRAFT_VERSION = "1.20";
|
||||
|
||||
/**
|
||||
* The maximum version MoreMobHeads has been tested with.
|
||||
*/
|
||||
public static final String MAXIMUM_MINECRAFT_VERSION = "1.20.4";
|
||||
|
||||
/**
|
||||
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.20.4) was released.
|
||||
*/
|
||||
public static final String MINECRAFT_LAST_RELEASE_DATE = "2023-12-07";
|
||||
|
||||
/**
|
||||
* Plugins that are currently incompatible with MoreMobHeads.
|
||||
*/
|
||||
public static final List<String> INCOMPATIBLE = ImmutableList.of("");
|
||||
|
||||
private static Plugin plugin;
|
||||
|
||||
private static boolean updatesDisabled;
|
||||
private static boolean initialized;
|
||||
private static ErrorReporter reporter = new BasicErrorReporter();
|
||||
|
||||
protected static void init(Plugin plugin, ErrorReporter reporter) {
|
||||
Validate.isTrue(!initialized, "MoreMobHeads has already been initialized.");
|
||||
PluginLibrary.plugin = plugin;
|
||||
PluginLibrary.reporter = reporter;
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
// Every possible error or warning report type
|
||||
public static final ReportType REPORT_CANNOT_DELETE_CONFIG = new ReportType("Cannot delete old MoreMobHeads configuration.");
|
||||
|
||||
public static final ReportType REPORT_METRICS_LOAD_ERROR = new ReportType("Cannot load bStats Metrics.");
|
||||
|
||||
public static final ReportType REPORT_PLUGIN_LOAD_ERROR = new ReportType("Cannot load MoreMobHeads.");
|
||||
public static final ReportType REPORT_CANNOT_LOAD_CONFIG = new ReportType("Cannot load configuration");
|
||||
public static final ReportType REPORT_CANNOT_CHECK_CONFIG = new ReportType("Cannot check configuration");
|
||||
public static final ReportType REPORT_CANNOT_SAVE_CONFIG = new ReportType("Cannot save configuration");
|
||||
public static final ReportType REPORT_PLUGIN_ENABLE_ERROR = new ReportType("Cannot enable MoreMobHeads.");
|
||||
public static final ReportType REPORT_PLUGIN_UNKNOWN_ERROR = new ReportType("Unknown Error");
|
||||
|
||||
public static final ReportType REPORT_MESSAGES_LOAD_ERROR = new ReportType("Could not load messages.yml");
|
||||
public static final ReportType REPORT_MESSAGES_COPY_ERROR = new ReportType("Could not copy messages.yml to old_messages.yml");
|
||||
public static final ReportType REPORT_OLDMESSAGES_LOAD_ERROR = new ReportType("Could not load old_messages.yml");
|
||||
public static final ReportType REPORT_OLDMESSAGES_SAVE_ERROR = new ReportType("Could not save old messages to messages.yml");
|
||||
public static final ReportType REPORT_PLAYERHEAD_LOAD_ERROR = new ReportType("Could not load player_heads.yml");
|
||||
public static final ReportType REPORT_CUSTOM_LOAD_ERROR = new ReportType("Could not load custom_trades.yml");
|
||||
public static final ReportType REPORT_CHANCE_LOAD_ERROR = new ReportType("Could not load chance_config.yml");
|
||||
public static final ReportType REPORT_CHANCE_SAVE_ERROR = new ReportType("Could not save chance_config.yml");
|
||||
public static final ReportType REPORT_CHANCE_COPY_ERROR = new ReportType("Could not copy chance_config.yml to old_chance_config.yml");
|
||||
public static final ReportType REPORT_MOBNAMES_LOAD_ERROR = new ReportType("Could not load lang_mobnames file");
|
||||
|
||||
public static final ReportType REPORT_PIE_LOAD_ERROR = new ReportType("Error with naming mob.");
|
||||
public static final ReportType REPORT_HEAD_URL_ERROR = new ReportType("Malformed URL Error");
|
||||
public static final ReportType REPORT_BLOCKHEAD_LOAD_ERROR = new ReportType("Cannot load BlockHeads file");
|
||||
|
||||
public static final ReportType REPORT_METRICS_IO_ERROR = new ReportType("Unable to enable metrics due to network problems.");
|
||||
public static final ReportType REPORT_METRICS_GENERIC_ERROR = new ReportType("Unable to enable metrics due to network problems.");
|
||||
|
||||
public static final ReportType REPORT_CANNOT_PARSE_MINECRAFT_VERSION = new ReportType("Unable to retrieve current Minecraft version. Assuming %s");
|
||||
public static final ReportType REPORT_CANNOT_DETECT_CONFLICTING_PLUGINS = new ReportType("Unable to detect conflicting plugin versions.");
|
||||
public static final ReportType REPORT_CANNOT_REGISTER_COMMAND = new ReportType("Cannot register command %s: %s");
|
||||
|
||||
public static final ReportType REPORT_CANNOT_CREATE_TIMEOUT_TASK = new ReportType("Unable to create packet timeout task.");
|
||||
public static final ReportType REPORT_CANNOT_UPDATE_PLUGIN = new ReportType("Cannot perform automatic updates.");
|
||||
|
||||
public static final ReportType REPORT_CANNOT_GET_HEXNICK = new ReportType("Cannot get Nick from HexNicks.");
|
||||
|
||||
public static final ReportType REPORT_PLAYER_NAMED_MOB = new ReportType("Unable to parse named mob kill.");
|
||||
public static final ReportType REPORT_PLAYER_KILL_PLAYER = new ReportType("Unable to parse Player Death.");
|
||||
public static final ReportType REPORT_WHITE_BLACK_LIST = new ReportType("Unable to parse global whitelist/blacklist.");
|
||||
public static final ReportType REPORT_PLAYER_KILL_MOB = new ReportType("Unable to parse Mob Kill.");
|
||||
public static final ReportType REPORT_EDBE_EVENT_ERROR = new ReportType("Unable to get damager weapon.");
|
||||
public static final ReportType REPORT_EVENT_HANDLER_LOAD = new ReportType("Error while loading EventHandler.");
|
||||
public static final ReportType REPORT_CS_EVENT_ERROR = new ReportType("Error while entity spawning.");
|
||||
public static final ReportType REPORT_ANNOUNCE_ERROR = new ReportType("Error announcing beheading.");
|
||||
public static final ReportType REPORT_RESOLVE_DAMAGE_WEAPON = new ReportType("Error resolving the Damaging Weapon.");
|
||||
public static final ReportType REPORT_GET_WEAPON_ERROR = new ReportType("Error getting weapon.");
|
||||
public static final ReportType REPORT_TAB_COMPLETE_ERROR = new ReportType("Error parsing Tab Complete.");
|
||||
|
||||
public static final ReportType REPORT_COMMAND_MENU_ERROR = new ReportType("Error displaying Command Menu.");
|
||||
public static final ReportType REPORT_COMMAND_HEADNBT_ERROR = new ReportType("Error executing HeadNBT command.");
|
||||
public static final ReportType REPORT_COMMAND_DISPLAY_PERMS = new ReportType("Error executing Display Perms command.");
|
||||
public static final ReportType REPORT_COMMAND_DISPLAY_VARS = new ReportType("Error executing Display Vars command.");
|
||||
public static final ReportType REPORT_COMMAND_DISPLAY_CHANCE = new ReportType("Error executing Display Chance command.");
|
||||
public static final ReportType REPORT_COMMAND_RELOAD_ERROR = new ReportType("Error executing Reload command.");
|
||||
public static final ReportType REPORT_COMMAND_TOGGLE_DEBUG = new ReportType("Error executing ToggleDebug Command.");
|
||||
public static final ReportType REPORT_COMMAND_CUSTOM_TRADER = new ReportType("Error executing CustomTrader Command.");
|
||||
public static final ReportType REPORT_COMMAND_PLAYER_HEADS = new ReportType("Error executing PlayerHeads Command.");
|
||||
public static final ReportType REPORT_COMMAND_FIX_HEAD = new ReportType("Error executing Fixhead Command.");
|
||||
public static final ReportType REPORT_COMMAND_GIVE_MH = new ReportType("Error executing GiveMH Command.");
|
||||
public static final ReportType REPORT_COMMAND_GIVE_PH = new ReportType("Error executing GivePH Command.");
|
||||
public static final ReportType REPORT_COMMAND_GIVE_BH = new ReportType("Error executing GiveBH Command.");
|
||||
public static final ReportType REPORT_COMMAND_DEV_ERROR = new ReportType("Error exuting dev Command.");
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the MoreMobHeads plugin instance.
|
||||
* @return The plugin instance
|
||||
*/
|
||||
public static Plugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the MoreMobHeads update checker.
|
||||
*/
|
||||
public static void disableUpdates() {
|
||||
updatesDisabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current error reporter.
|
||||
* @return Current error reporter.
|
||||
*/
|
||||
public static ErrorReporter getErrorReporter() {
|
||||
return reporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether updates are currently disabled.
|
||||
* @return True if it is, false if not
|
||||
*/
|
||||
public static boolean updatesDisabled() {
|
||||
return updatesDisabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.github.joelgodofwar.mmh.common;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
import com.github.joelgodofwar.mmh.MoreMobHeads;
|
||||
import com.github.joelgodofwar.mmh.util.MinecraftVersion;
|
||||
|
||||
/**
|
||||
* Custom logger for the MoreMobHeads plugin.
|
||||
*/
|
||||
public class PluginLogger {
|
||||
private Logger logger = Logger.getLogger("Minecraft");
|
||||
private MoreMobHeads mmh;
|
||||
|
||||
/**
|
||||
* Constructor for the PluginLogger class.
|
||||
* @param plugin The MoreMobHeads plugin instance.
|
||||
*/
|
||||
public PluginLogger(MoreMobHeads plugin) {
|
||||
logger = plugin.getLogger();
|
||||
mmh = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a message to console with the INFO level.
|
||||
* @param message Message to log.
|
||||
*/
|
||||
public void log(String message) {
|
||||
log(message, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a message to console with a given level.
|
||||
* @param level Logging level
|
||||
* @param message Message to log
|
||||
* @param args Arguments to format in
|
||||
*/
|
||||
public void log(Level level, String message, Object... args) {
|
||||
String pluginName = ChatColor.RESET + "[" + ChatColor.YELLOW + mmh.getName() + ChatColor.RESET + "] ";
|
||||
if (!areAllArgsBlank(args)) {
|
||||
//logger.log(level, applyColorFormatting(MessageFormat.format(message, args)));
|
||||
Bukkit.getConsoleSender().sendMessage(pluginName + MessageFormat.format(pluginName + message, args));
|
||||
} else {
|
||||
//logger.log(level, applyColorFormatting(message));
|
||||
Bukkit.getConsoleSender().sendMessage(pluginName + message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a method to console with the INFO level.
|
||||
* @param message Message to log
|
||||
* @param args Arguments to format in
|
||||
*/
|
||||
public void log(String message, Object... args) {
|
||||
log(Level.INFO, message, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a message to console with a given level and exception.
|
||||
* @param level Logging level
|
||||
* @param message Message to log
|
||||
* @param ex Exception to log
|
||||
*/
|
||||
public void log(Level level, String message, Throwable ex) {
|
||||
logger.log(level, message, ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a debug message to console if debugging is enabled.
|
||||
* @param message Debug message to log.
|
||||
*/
|
||||
public void debug(String message) {
|
||||
debug(message, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a debug message to console with arguments if debugging is enabled.
|
||||
* @param message Debug message to log.
|
||||
* @param args Arguments to format in the debug message.
|
||||
*/
|
||||
public void debug(String message, Object... args) {
|
||||
if (mmh.debug) {
|
||||
log("[Debug] " + message, args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a debug message to console with an exception if debugging is enabled.
|
||||
* @param message Debug message to log.
|
||||
* @param ex Exception to log.
|
||||
*/
|
||||
public void debug(String message, Throwable ex) {
|
||||
if (mmh.debug) {
|
||||
log(Level.WARNING, "[Debug] " + message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a warning message to console with the WARNING level.
|
||||
* @param message Warning message to log.
|
||||
*/
|
||||
public void warn(String message) {
|
||||
warn(message, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a warning message to console with the WARNING level and arguments.
|
||||
* @param message Warning message to log.
|
||||
* @param args Arguments to format in the warning message.
|
||||
*/
|
||||
public void warn(String message, Object... args) {
|
||||
log(Level.WARNING, "[Warning] " + message, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a warning message to console with the WARNING level if the Minecraft version is at or above a specified version.
|
||||
* @param version The Minecraft version to compare against.
|
||||
* @param message Warning message to log.
|
||||
* @param args Arguments to format in the warning message.
|
||||
*/
|
||||
public void warnAbove(MinecraftVersion version, String message, Object... args) {
|
||||
if (version.atOrAbove()) {
|
||||
log(Level.WARNING, message, args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if all arguments are null or blank.
|
||||
* @param args Arguments to check
|
||||
* @return true if all arguments are null or blank, false otherwise
|
||||
*/
|
||||
private boolean areAllArgsBlank(Object... args) {
|
||||
if ((args == null) || (args.length == 0)) {
|
||||
return true; // Null or empty arguments are considered blank
|
||||
}
|
||||
for (Object arg : args) {
|
||||
if ((arg == null) || ((arg instanceof String) && ((String) arg).isEmpty())) {
|
||||
continue; // Skip null or empty string
|
||||
} else {
|
||||
return false; // Found a non-blank argument
|
||||
}
|
||||
}
|
||||
return true; // All arguments are null or blank
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
package com.github.joelgodofwar.mmh.common.collections;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Ticker;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.primitives.Longs;
|
||||
|
||||
/**
|
||||
* Represents a hash map where each association may expire after a given time has elapsed.
|
||||
* <p>
|
||||
* Note that replaced key-value associations are only collected once the original expiration time has elapsed.
|
||||
*
|
||||
* @author Kristian Stangeland
|
||||
*
|
||||
* @param <K> - type of the keys.
|
||||
* @param <V> - type of the values.
|
||||
*/
|
||||
public class ExpireHashMap<K, V> {
|
||||
private class ExpireEntry implements Comparable<ExpireEntry> {
|
||||
public final long expireTime;
|
||||
public final K expireKey;
|
||||
public final V expireValue;
|
||||
|
||||
public ExpireEntry(long expireTime, K expireKey, V expireValue) {
|
||||
this.expireTime = expireTime;
|
||||
this.expireKey = expireKey;
|
||||
this.expireValue = expireValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ExpireEntry o) {
|
||||
return Longs.compare(expireTime, o.expireTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ExpireEntry [expireTime=" + expireTime + ", expireKey=" + expireKey
|
||||
+ ", expireValue=" + expireValue + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private final Map<K, ExpireEntry> keyLookup = new HashMap<>();
|
||||
private final PriorityQueue<ExpireEntry> expireQueue = new PriorityQueue<>();
|
||||
|
||||
// View of keyLookup with direct values
|
||||
private final Map<K, V> valueView = Maps.transformValues(keyLookup, entry -> entry.expireValue);
|
||||
|
||||
// Supplied by the constructor
|
||||
private final Ticker ticker;
|
||||
|
||||
/**
|
||||
* Construct a new hash map where each entry may expire at a given time.
|
||||
*/
|
||||
public ExpireHashMap() {
|
||||
this(Ticker.systemTicker());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new hash map where each entry may expire at a given time.
|
||||
* @param ticker - supplier of the current time.
|
||||
*/
|
||||
public ExpireHashMap(Ticker ticker) {
|
||||
this.ticker = ticker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value associated with the given key, if it has not expired.
|
||||
* @param key - the key.
|
||||
* @return The value, or NULL if not found or it has expired.
|
||||
*/
|
||||
public V get(K key) {
|
||||
evictExpired();
|
||||
|
||||
ExpireEntry entry = keyLookup.get(key);
|
||||
return entry != null ? entry.expireValue : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the given key with the given value, until the expire delay have elapsed.
|
||||
* @param key - the key.
|
||||
* @param value - the value.
|
||||
* @param expireDelay - the amount of time until this association expires. Must be greater than zero.
|
||||
* @param expireUnit - the unit of the expiration.
|
||||
* @return Any previously unexpired association with this key, or NULL.
|
||||
*/
|
||||
public V put(K key, V value, long expireDelay, TimeUnit expireUnit) {
|
||||
Preconditions.checkNotNull(expireUnit, "expireUnit cannot be NULL");
|
||||
Preconditions.checkState(expireDelay > 0, "expireDelay cannot be equal or less than zero.");
|
||||
evictExpired();
|
||||
|
||||
ExpireEntry entry = new ExpireEntry(
|
||||
ticker.read() + TimeUnit.NANOSECONDS.convert(expireDelay, expireUnit),
|
||||
key, value
|
||||
);
|
||||
ExpireEntry previous = keyLookup.put(key, entry);
|
||||
|
||||
// We enqueue its removal
|
||||
expireQueue.add(entry);
|
||||
return previous != null ? previous.expireValue : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given key is referring to an unexpired association in the map.
|
||||
* @param key - the key.
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public boolean containsKey(K key) {
|
||||
evictExpired();
|
||||
return keyLookup.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given value is referring to an unexpired association in the map.
|
||||
* @param value - the value.
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public boolean containsValue(V value) {
|
||||
evictExpired();
|
||||
|
||||
// Linear scan is the best we've got
|
||||
for (ExpireEntry entry : keyLookup.values()) {
|
||||
if (Objects.equal(value, entry.expireValue)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a key and its associated value from the map.
|
||||
* @param key - the key to remove.
|
||||
* @return Value of the removed association, NULL otherwise.
|
||||
*/
|
||||
public V removeKey(K key) {
|
||||
evictExpired();
|
||||
|
||||
ExpireEntry entry = keyLookup.remove(key);
|
||||
return entry != null ? entry.expireValue : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the number of entries in the map.
|
||||
* @return The number of entries.
|
||||
*/
|
||||
public int size() {
|
||||
evictExpired();
|
||||
return keyLookup.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a view of the keys in the current map.
|
||||
* @return View of the keys.
|
||||
*/
|
||||
public Set<K> keySet() {
|
||||
evictExpired();
|
||||
return keyLookup.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a view of all the values in the current map.
|
||||
* @return All the values.
|
||||
*/
|
||||
public Collection<V> values() {
|
||||
evictExpired();
|
||||
return valueView.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a view of all the entries in the set.
|
||||
* @return All the entries.
|
||||
*/
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
evictExpired();
|
||||
return valueView.entrySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a view of this expire map as an ordinary map that does not support insertion.
|
||||
* @return The map.
|
||||
*/
|
||||
public Map<K, V> asMap() {
|
||||
evictExpired();
|
||||
return valueView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all references to key-value pairs that have been removed or replaced before they were naturally evicted.
|
||||
* <p>
|
||||
* This operation requires a linear scan of the current entries in the map.
|
||||
*/
|
||||
public void collect() {
|
||||
// First evict what we can
|
||||
evictExpired();
|
||||
|
||||
// Recreate the eviction queue - this is faster than removing entries in the old queue
|
||||
expireQueue.clear();
|
||||
expireQueue.addAll(keyLookup.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all the entries in the current map.
|
||||
*/
|
||||
public void clear() {
|
||||
keyLookup.clear();
|
||||
expireQueue.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Evict any expired entries in the map.
|
||||
* <p>
|
||||
* This is called automatically by any of the read or write operations.
|
||||
*/
|
||||
protected void evictExpired() {
|
||||
long currentTime = ticker.read();
|
||||
|
||||
// Remove expired entries
|
||||
while ((expireQueue.size() > 0) && (expireQueue.peek().expireTime <= currentTime)) {
|
||||
ExpireEntry entry = expireQueue.poll();
|
||||
|
||||
if (entry == keyLookup.get(entry.expireKey)) {
|
||||
keyLookup.remove(entry.expireKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return valueView.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.github.joelgodofwar.mmh.common.error;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.github.joelgodofwar.mmh.common.error.Report.ReportBuilder;
|
||||
import com.github.joelgodofwar.mmh.common.reflect.PrettyPrinter;
|
||||
|
||||
/**
|
||||
* Represents a basic error reporter that prints error reports to the standard error stream.
|
||||
* <p>
|
||||
* Note that this implementation doesn't distinguish between {@link #reportWarning(Object, Report)}
|
||||
* and {@link #reportDetailed(Object, Report)} - they both have the exact same behavior.
|
||||
* @author Kristian
|
||||
*/
|
||||
public class BasicErrorReporter implements ErrorReporter {
|
||||
private final PrintStream output;
|
||||
|
||||
/**
|
||||
* Construct a new basic error reporter that prints directly the standard error stream.
|
||||
*/
|
||||
public BasicErrorReporter() {
|
||||
this(System.err);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a error reporter that prints to the given output stream.
|
||||
* @param output - the output stream.
|
||||
*/
|
||||
public BasicErrorReporter(PrintStream output) {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportMinimal(Plugin sender, String methodName, Throwable error) {
|
||||
output.println("Unhandled exception occured in " + methodName + " for " + sender.getName());
|
||||
error.printStackTrace(output);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters) {
|
||||
reportMinimal(sender, methodName, error);
|
||||
|
||||
// Also print parameters
|
||||
printParameters(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportDebug(Object sender, Report report) {
|
||||
// We just have to swallow it
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportDebug(Object sender, ReportBuilder builder) {
|
||||
// As above
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportWarning(Object sender, Report report) {
|
||||
// Basic warning
|
||||
output.println("[" + sender.getClass().getSimpleName() + "] " + report.getReportMessage());
|
||||
|
||||
if (report.getException() != null) {
|
||||
report.getException().printStackTrace(output);
|
||||
}
|
||||
printParameters(report.getCallerParameters());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportWarning(Object sender, ReportBuilder reportBuilder) {
|
||||
reportWarning(sender, reportBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportDetailed(Object sender, Report report) {
|
||||
// No difference from warning
|
||||
reportWarning(sender, report);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportDetailed(Object sender, ReportBuilder reportBuilder) {
|
||||
reportWarning(sender, reportBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the given parameters to the standard error stream.
|
||||
* @param parameters - the output parameters.
|
||||
*/
|
||||
private void printParameters(Object[] parameters) {
|
||||
if ((parameters != null) && (parameters.length > 0)) {
|
||||
output.println("Parameters: ");
|
||||
|
||||
try {
|
||||
for (Object parameter : parameters) {
|
||||
if (parameter == null) {
|
||||
output.println("[NULL]");
|
||||
} else {
|
||||
output.println(PrettyPrinter.printObject(parameter));
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
// Damn it
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,663 @@
|
||||
package com.github.joelgodofwar.mmh.common.error;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringStyle;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.github.joelgodofwar.mmh.MoreMobHeads;
|
||||
import com.github.joelgodofwar.mmh.common.collections.ExpireHashMap;
|
||||
import com.github.joelgodofwar.mmh.common.error.Report.ReportBuilder;
|
||||
import com.github.joelgodofwar.mmh.common.reflect.PrettyPrinter;
|
||||
import com.github.joelgodofwar.mmh.util.Ansi;
|
||||
import com.github.joelgodofwar.mmh.util.StrUtils;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.primitives.Primitives;
|
||||
|
||||
/**
|
||||
* Internal class used to handle exceptions.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class DetailedErrorReporter implements ErrorReporter {
|
||||
/**
|
||||
* Report format for printing the current exception count.
|
||||
*/
|
||||
public static final ReportType REPORT_EXCEPTION_COUNT = new ReportType("Internal exception count: %s!");
|
||||
|
||||
public static final String SECOND_LEVEL_PREFIX = " ";
|
||||
public static final String DEFAULT_PREFIX = " ";
|
||||
public static final String DEFAULT_SUPPORT_URL = "https://discord.gg/Fq9HQ2dmtd";
|
||||
|
||||
// Users that are informed about errors in the chat
|
||||
public static final String ERROR_PERMISSION = "protocol.info";
|
||||
|
||||
// We don't want to spam the server
|
||||
public static final int DEFAULT_MAX_ERROR_COUNT = 20;
|
||||
|
||||
// Prevent spam per plugin too
|
||||
private ConcurrentMap<String, AtomicInteger> warningCount = new ConcurrentHashMap<String, AtomicInteger>();
|
||||
|
||||
protected String prefix;
|
||||
protected String supportURL;
|
||||
|
||||
protected AtomicInteger internalErrorCount = new AtomicInteger();
|
||||
|
||||
protected int maxErrorCount;
|
||||
protected Logger logger;
|
||||
|
||||
protected WeakReference<Plugin> pluginReference;
|
||||
protected String pluginName;
|
||||
|
||||
// Whether or not Apache Commons is not present
|
||||
protected static boolean apacheCommonsMissing;
|
||||
|
||||
// Whether or not detailed errror reporting is enabled
|
||||
protected boolean detailedReporting;
|
||||
|
||||
// Map of global objects
|
||||
protected Map<String, Object> globalParameters = new HashMap<String, Object>();
|
||||
|
||||
// Reports to ignore
|
||||
private ExpireHashMap<Report, Boolean> rateLimited = new ExpireHashMap<Report, Boolean>();
|
||||
private final Object rateLock = new Object();
|
||||
private MoreMobHeads mmh;
|
||||
|
||||
/**
|
||||
* Create a default error reporting system.
|
||||
* @param plugin - the plugin owner.
|
||||
*/
|
||||
public DetailedErrorReporter(Plugin plugin) {
|
||||
this(plugin, DEFAULT_PREFIX, DEFAULT_SUPPORT_URL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a central error reporting system.
|
||||
* @param plugin - the plugin owner.
|
||||
* @param prefix - default line prefix.
|
||||
* @param supportURL - URL to report the error.
|
||||
*/
|
||||
public DetailedErrorReporter(Plugin plugin, String prefix, String supportURL) {
|
||||
this(plugin, prefix, supportURL, DEFAULT_MAX_ERROR_COUNT, getBukkitLogger());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a central error reporting system.
|
||||
* @param plugin - the plugin owner.
|
||||
* @param prefix - default line prefix.
|
||||
* @param supportURL - URL to report the error.
|
||||
* @param maxErrorCount - number of errors to print before giving up.
|
||||
* @param LOGGER - current logger.
|
||||
*/
|
||||
public DetailedErrorReporter(Plugin plugin, String prefix, String supportURL, int maxErrorCount, Logger logger) {
|
||||
if (plugin == null) {
|
||||
throw new IllegalArgumentException("Plugin cannot be NULL.");
|
||||
}
|
||||
|
||||
this.pluginReference = new WeakReference<Plugin>(plugin);
|
||||
this.pluginName = getNameSafely(plugin);
|
||||
this.prefix = prefix;
|
||||
this.supportURL = supportURL;
|
||||
this.maxErrorCount = maxErrorCount;
|
||||
this.logger = logger;
|
||||
this.mmh = (MoreMobHeads) plugin;
|
||||
}
|
||||
|
||||
private String getNameSafely(Plugin plugin) {
|
||||
try {
|
||||
return plugin.getName();
|
||||
} catch (LinkageError e) {
|
||||
return "MoreMobHeads";
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to get the logger.
|
||||
private static Logger getBukkitLogger() {
|
||||
try {
|
||||
return Bukkit.getLogger();
|
||||
} catch (LinkageError e) {
|
||||
return Logger.getLogger("Minecraft");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we're using detailed error reporting.
|
||||
* @return TRUE if we are, FALSE otherwise.
|
||||
*/
|
||||
public boolean isDetailedReporting() {
|
||||
return detailedReporting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not to use detailed error reporting.
|
||||
* @param detailedReporting - TRUE to enable it, FALSE otherwise.
|
||||
*/
|
||||
public void setDetailedReporting(boolean detailedReporting) {
|
||||
this.detailedReporting = detailedReporting;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters) {
|
||||
if (reportMinimalNoSpam(sender, methodName, error)) {
|
||||
// Print parameters, if they are given
|
||||
if ((parameters != null) && (parameters.length > 0)) {
|
||||
logger.log(Level.SEVERE, printParameters(parameters));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportMinimal(Plugin sender, String methodName, Throwable error) {
|
||||
reportMinimalNoSpam(sender, methodName, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a problem with a given method and plugin, ensuring that we don't exceed the maximum number of error reports.
|
||||
* @param sender - the component that observed this exception.
|
||||
* @param methodName - the method name.
|
||||
* @param error - the error itself.
|
||||
* @return TRUE if the error was printed, FALSE if it was suppressed.
|
||||
*/
|
||||
public boolean reportMinimalNoSpam(Plugin sender, String methodName, Throwable error) {
|
||||
String pluginName = sender.getName();
|
||||
AtomicInteger counter = warningCount.get(pluginName);
|
||||
|
||||
// Thread safe pattern
|
||||
if (counter == null) {
|
||||
AtomicInteger created = new AtomicInteger();
|
||||
counter = warningCount.putIfAbsent(pluginName, created);
|
||||
|
||||
if (counter == null) {
|
||||
counter = created;
|
||||
}
|
||||
}
|
||||
|
||||
final int errorCount = counter.incrementAndGet();
|
||||
|
||||
// See if we should print the full error
|
||||
if (errorCount < getMaxErrorCount()) {
|
||||
logger.log(Level.SEVERE, "[" + pluginName + "] Unhandled exception occurred in " +
|
||||
methodName + " for " + pluginName, error);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// Nope - only print the error count occasionally
|
||||
if (isPowerOfTwo(errorCount)) {
|
||||
logger.log(Level.SEVERE, "[" + pluginName + "] Unhandled exception number " + errorCount + " occurred in " +
|
||||
methodName + " for " + pluginName, error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given number is a power of two.
|
||||
* <p>
|
||||
* That is, if there exists an N such that 2^N = number.
|
||||
* @param number - the number to check.
|
||||
* @return TRUE if the given number is a power of two, FALSE otherwise.
|
||||
*/
|
||||
private boolean isPowerOfTwo(int number) {
|
||||
return (number & (number - 1)) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportDebug(Object sender, ReportBuilder builder) {
|
||||
reportDebug(sender, Preconditions.checkNotNull(builder, "builder cannot be NULL").build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportDebug(Object sender, Report report) {
|
||||
if (logger.isLoggable(Level.FINE) && canReport(report)) {
|
||||
reportLevel(Level.FINE, sender, report);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportWarning(Object sender, ReportBuilder reportBuilder) {
|
||||
if (reportBuilder == null) {
|
||||
throw new IllegalArgumentException("reportBuilder cannot be NULL.");
|
||||
}
|
||||
|
||||
reportWarning(sender, reportBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportWarning(Object sender, Report report) {
|
||||
if (logger.isLoggable(Level.WARNING) && canReport(report)) {
|
||||
reportLevel(Level.WARNING, sender, report);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we should print the given report.
|
||||
* <p>
|
||||
* The default implementation will check for rate limits.
|
||||
* @param report - the report to check.
|
||||
* @return TRUE if we should print it, FALSE otherwise.
|
||||
*/
|
||||
protected boolean canReport(Report report) {
|
||||
long rateLimit = report.getRateLimit();
|
||||
|
||||
// Check for rate limit
|
||||
if (rateLimit > 0) {
|
||||
synchronized (rateLock) {
|
||||
if (rateLimited.containsKey(report)) {
|
||||
return false;
|
||||
}
|
||||
rateLimited.put(report, true, rateLimit, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void reportLevel(Level level, Object sender, Report report) {
|
||||
String message = "[" + pluginName + "] [" + getSenderName(sender) + "] " + report.getReportMessage();
|
||||
|
||||
// Print the main warning
|
||||
if (report.getException() != null) {
|
||||
logger.log(level, message, report.getException());
|
||||
} else {
|
||||
logger.log(level, message);
|
||||
|
||||
// Remember the call stack
|
||||
if (detailedReporting) {
|
||||
printCallStack(level, logger);
|
||||
}
|
||||
}
|
||||
|
||||
// Parameters?
|
||||
if (report.hasCallerParameters()) {
|
||||
// Write it
|
||||
logger.log(level, printParameters(report.getCallerParameters()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the name of a sender class.
|
||||
* @param sender - sender object.
|
||||
* @return The name of the sender's class.
|
||||
*/
|
||||
private String getSenderName(Object sender) {
|
||||
if (sender != null) {
|
||||
return ReportType.getSenderClass(sender).getSimpleName();
|
||||
} else {
|
||||
return "NULL";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportDetailed(Object sender, ReportBuilder reportBuilder) {
|
||||
reportDetailed(sender, reportBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportDetailed(Object sender, Report report) {
|
||||
final Plugin plugin = pluginReference.get();
|
||||
final int errorCount = internalErrorCount.incrementAndGet();
|
||||
|
||||
// Do not overtly spam the server!
|
||||
if (errorCount > getMaxErrorCount()) {
|
||||
// Only allow the error count at rare occations
|
||||
if (isPowerOfTwo(errorCount)) {
|
||||
// Permit it - but print the number of exceptions first
|
||||
reportWarning(this, Report.newBuilder(REPORT_EXCEPTION_COUNT).messageParam(errorCount).build());
|
||||
} else {
|
||||
// NEVER SPAM THE CONSOLE
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Secondary rate limit
|
||||
if (!canReport(report)) {
|
||||
return;
|
||||
}
|
||||
|
||||
StringWriter text = new StringWriter();
|
||||
PrintWriter writer = new PrintWriter(text);
|
||||
|
||||
// Helpful message
|
||||
writer.println("[" + pluginName + "] INTERNAL ERROR: " + report.getReportMessage());
|
||||
writer.println("Copy from above line down to ↓↓↓");
|
||||
writer.println("If this problem hasn't already been reported, please post");
|
||||
writer.println("at " + supportURL + " with the following data:");
|
||||
|
||||
// Data dump!
|
||||
writer.println("Data Dump:");
|
||||
|
||||
// Relevant parameters
|
||||
if (report.hasCallerParameters()) {
|
||||
printParameters(writer, report.getCallerParameters());
|
||||
}
|
||||
|
||||
// Global parameters
|
||||
for (String param : globalParameters()) {
|
||||
writer.println(SECOND_LEVEL_PREFIX + param + ":");
|
||||
writer.println(addPrefix(getStringDescription(getGlobalParameter(param)),
|
||||
SECOND_LEVEL_PREFIX + SECOND_LEVEL_PREFIX));
|
||||
}
|
||||
|
||||
// Now, for the sender itself
|
||||
writer.println("Sender:");
|
||||
writer.println(addPrefix(getStringDescription(sender), SECOND_LEVEL_PREFIX));
|
||||
|
||||
// And plugin
|
||||
if (plugin != null) {
|
||||
writer.println("Version: " + mmh.getName() + " v" + mmh.getDescription().getVersion());
|
||||
String jarfilename = mmh.getjarfilename();
|
||||
writer.println(addPrefix("jarfilename: " + StrUtils.Right(jarfilename, jarfilename.length() - jarfilename.lastIndexOf(File.separatorChar)), SECOND_LEVEL_PREFIX));
|
||||
//writer.println(addPrefix(plugin.toString(), SECOND_LEVEL_PREFIX));
|
||||
}
|
||||
|
||||
writer.println("config.yml:");
|
||||
FileConfiguration config = mmh.getConfig();
|
||||
for (String key : config.getKeys(true)) {
|
||||
Object value = config.get(key);
|
||||
if ((value != null) && value.getClass().isArray()) {
|
||||
value = Arrays.asList((Object[]) value);
|
||||
}
|
||||
if ((value != null) && value.toString().contains("MemorySection")) {
|
||||
value = "";
|
||||
}
|
||||
writer.println(addPrefix( key + " = '" + value + "'" , SECOND_LEVEL_PREFIX));
|
||||
}
|
||||
|
||||
// And java version
|
||||
writer.println("Java Version: " + System.getProperty("java.version"));
|
||||
//writer.println(addPrefix(System.getProperty("java.version"), SECOND_LEVEL_PREFIX));
|
||||
|
||||
// Add the server version too
|
||||
if (Bukkit.getServer() != null) {
|
||||
writer.println("Server: ");
|
||||
writer.println(addPrefix("This server is running " + Bukkit.getName() + " version " + Bukkit.getVersion() + " (Implementing API version " + Bukkit.getBukkitVersion() + ")", SECOND_LEVEL_PREFIX));
|
||||
/** add list of all plugins, and their version */
|
||||
writer.println(getPluginList());
|
||||
|
||||
|
||||
// Inform of this occurrence
|
||||
if (isChatWarnings()) {
|
||||
Bukkit.getServer().broadcast(
|
||||
String.format("Error %s (%s) occurred in %s.", report.getReportMessage(), report.getException(), sender),
|
||||
ERROR_PERMISSION
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Now, let us print important exception information
|
||||
writer.println("Stack Trace:");
|
||||
|
||||
if (report.getException() != null) {
|
||||
report.getException().printStackTrace(writer);
|
||||
} else if (detailedReporting) {
|
||||
printCallStack(writer);
|
||||
}
|
||||
writer.println("-> -> -> -> -> -> -> -> This line <- <- <- <- <- <- <- <-");
|
||||
|
||||
// Make sure it is reported
|
||||
logger.severe(addPrefix(text.toString(), prefix));
|
||||
}
|
||||
|
||||
private boolean isChatWarnings() {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the call stack to the given logger.
|
||||
* @param logger - the logger.
|
||||
*/
|
||||
private void printCallStack(Level level, Logger logger) {
|
||||
StringWriter text = new StringWriter();
|
||||
printCallStack(new PrintWriter(text));
|
||||
|
||||
// Print the exception
|
||||
logger.log(level, text.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the current call stack.
|
||||
* @param writer - the writer.
|
||||
*/
|
||||
private void printCallStack(PrintWriter writer) {
|
||||
Exception current = new Exception("Not an error! This is the call stack.");
|
||||
current.printStackTrace(writer);
|
||||
}
|
||||
|
||||
private String printParameters(Object... parameters) {
|
||||
StringWriter writer = new StringWriter();
|
||||
|
||||
// Print and retrieve the string buffer
|
||||
printParameters(new PrintWriter(writer), parameters);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
private void printParameters(PrintWriter writer, Object[] parameters) {
|
||||
writer.println("Parameters: ");
|
||||
|
||||
// We *really* want to get as much information as possible
|
||||
for (Object param : parameters) {
|
||||
writer.println(addPrefix(getStringDescription(param), SECOND_LEVEL_PREFIX));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given prefix to every line in the text.
|
||||
* @param text - text to modify.
|
||||
* @param prefix - prefix added to every line in the text.
|
||||
* @return The modified text.
|
||||
*/
|
||||
protected String addPrefix(String text, String prefix) {
|
||||
return text.replaceAll("(?m)^", prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a string representation of the given object.
|
||||
* @param value - object to convert.
|
||||
* @return String representation.
|
||||
*/
|
||||
public static String getStringDescription(Object value) {
|
||||
// We can't only rely on toString.
|
||||
if (value == null) {
|
||||
return "[NULL]";
|
||||
} if (isSimpleType(value) || (value instanceof Class<?>)) {
|
||||
return value.toString();
|
||||
} else {
|
||||
try {
|
||||
if (!apacheCommonsMissing) {
|
||||
return ToStringBuilder.reflectionToString(value, ToStringStyle.MULTI_LINE_STYLE, false, null);
|
||||
}
|
||||
} catch (LinkageError ex) {
|
||||
// Apache is probably missing
|
||||
apacheCommonsMissing = true;
|
||||
} catch (ThreadDeath | OutOfMemoryError e) {
|
||||
throw e;
|
||||
} catch (Throwable ex) {
|
||||
// Don't use the error logger to log errors in error logging (that could lead to infinite loops)
|
||||
getBukkitLogger().log(Level.WARNING, "Cannot convert to a String with Apache: " + ex.getMessage());
|
||||
}
|
||||
|
||||
// Use our custom object printer instead
|
||||
try {
|
||||
return PrettyPrinter.printObject(value, value.getClass(), Object.class);
|
||||
} catch (IllegalAccessException e) {
|
||||
return "[Error: " + e.getMessage() + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given object is a wrapper for a primitive/simple type or not.
|
||||
* @param test - the object to test.
|
||||
* @return TRUE if this object is simple enough to simply be printed, FALSE othewise.
|
||||
*/
|
||||
protected static boolean isSimpleType(Object test) {
|
||||
return (test instanceof String) || Primitives.isWrapperType(test.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current number of errors printed through {@link #reportDetailed(Object, Report)}.
|
||||
* @return Number of errors printed.
|
||||
*/
|
||||
public int getErrorCount() {
|
||||
return internalErrorCount.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of errors printed.
|
||||
* @param errorCount - new number of errors printed.
|
||||
*/
|
||||
public void setErrorCount(int errorCount) {
|
||||
internalErrorCount.set(errorCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the maximum number of errors we can print before we begin suppressing errors.
|
||||
* @return Maximum number of errors.
|
||||
*/
|
||||
public int getMaxErrorCount() {
|
||||
return maxErrorCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum number of errors we can print before we begin suppressing errors.
|
||||
* @param maxErrorCount - new max count.
|
||||
*/
|
||||
public void setMaxErrorCount(int maxErrorCount) {
|
||||
this.maxErrorCount = maxErrorCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given global parameter. It will be included in every error report.
|
||||
* <p>
|
||||
* Both key and value must be non-null.
|
||||
* @param key - name of parameter.
|
||||
* @param value - the global parameter itself.
|
||||
*/
|
||||
public void addGlobalParameter(String key, Object value) {
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("key cannot be NULL.");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException("value cannot be NULL.");
|
||||
}
|
||||
|
||||
globalParameters.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a global parameter by its key.
|
||||
* @param key - key of the parameter to retrieve.
|
||||
* @return The value of the global parameter, or NULL if not found.
|
||||
*/
|
||||
public Object getGlobalParameter(String key) {
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("key cannot be NULL.");
|
||||
}
|
||||
|
||||
return globalParameters.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all global parameters.
|
||||
*/
|
||||
public void clearGlobalParameters() {
|
||||
globalParameters.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a set of every registered global parameter.
|
||||
* @return Set of all registered global parameters.
|
||||
*/
|
||||
public Set<String> globalParameters() {
|
||||
return globalParameters.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the support URL that will be added to all detailed reports.
|
||||
* @return Support URL.
|
||||
*/
|
||||
public String getSupportURL() {
|
||||
return supportURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the support URL that will be added to all detailed reports.
|
||||
* @param supportURL - the new support URL.
|
||||
*/
|
||||
public void setSupportURL(String supportURL) {
|
||||
this.supportURL = supportURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the prefix to apply to every line in the error reports.
|
||||
* @return Error report prefix.
|
||||
*/
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the prefix to apply to every line in the error reports.
|
||||
* @param prefix - new prefix.
|
||||
*/
|
||||
public void setPrefix(String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current logger that is used to print all reports.
|
||||
* @return The current logger.
|
||||
*/
|
||||
public Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current logger that is used to print all reports.
|
||||
* @param logger - new logger.
|
||||
*/
|
||||
public void setLogger(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
private String getPluginList() {
|
||||
StringBuilder pluginList = new StringBuilder();
|
||||
Plugin[] plugins = Bukkit.getPluginManager().getPlugins();
|
||||
Plugin[] var6 = plugins;
|
||||
int var5 = plugins.length;
|
||||
|
||||
for (int var4 = 0; var4 < var5; ++var4) {
|
||||
Plugin plugin = var6[var4];
|
||||
if (pluginList.length() > 0) {
|
||||
pluginList.append(Ansi.WHITE);
|
||||
pluginList.append(", ");
|
||||
}
|
||||
|
||||
pluginList.append(plugin.isEnabled() ? Ansi.GREEN : Ansi.RED);
|
||||
pluginList.append(plugin.getDescription().getName());
|
||||
if (plugin.getDescription().getProvides().size() > 0) {
|
||||
pluginList.append(" (").append(String.join(", ", plugin.getDescription().getProvides())).append(")");
|
||||
}
|
||||
pluginList.append(" [" + plugin.getDescription().getVersion() + "]");
|
||||
}
|
||||
|
||||
return "Plugins (" + plugins.length + "): " + pluginList.toString() + Ansi.RESET;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.github.joelgodofwar.mmh.common.error;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.github.joelgodofwar.mmh.common.error.Report.ReportBuilder;
|
||||
|
||||
/**
|
||||
* Represents an object that can forward an error {@link Report} to the display and permanent storage.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public interface ErrorReporter {
|
||||
/**
|
||||
* Prints a small minimal error report regarding an exception from another plugin.
|
||||
* @param sender - the other plugin.
|
||||
* @param methodName - name of the caller method.
|
||||
* @param error - the exception itself.
|
||||
*/
|
||||
void reportMinimal(Plugin sender, String methodName, Throwable error);
|
||||
|
||||
/**
|
||||
* Prints a small minimal error report regarding an exception from another plugin.
|
||||
* @param sender - the other plugin.
|
||||
* @param methodName - name of the caller method.
|
||||
* @param error - the exception itself.
|
||||
* @param parameters - any relevant parameters to print.
|
||||
*/
|
||||
void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters);
|
||||
|
||||
/**
|
||||
* Prints a debug message from the current sender.
|
||||
* <p>
|
||||
* Most users will not see this message.
|
||||
* @param sender - the sender.
|
||||
* @param report - the report.
|
||||
*/
|
||||
void reportDebug(Object sender, Report report);
|
||||
|
||||
/**
|
||||
* Prints a debug message from the current sender.
|
||||
* @param sender - the sender.
|
||||
* @param builder - the report builder.
|
||||
*/
|
||||
void reportDebug(Object sender, ReportBuilder builder);
|
||||
|
||||
/**
|
||||
* Prints a warning message from the current plugin.
|
||||
* @param sender - the object containing the caller method.
|
||||
* @param report - an error report to include.
|
||||
*/
|
||||
void reportWarning(Object sender, Report report);
|
||||
|
||||
/**
|
||||
* Prints a warning message from the current plugin.
|
||||
* @param sender - the object containing the caller method.
|
||||
* @param reportBuilder - an error report builder that will be used to get the report.
|
||||
*/
|
||||
void reportWarning(Object sender, ReportBuilder reportBuilder);
|
||||
|
||||
/**
|
||||
* Prints a detailed error report about an unhandled exception.
|
||||
* @param sender - the object containing the caller method.
|
||||
* @param report - an error report to include.
|
||||
*/
|
||||
void reportDetailed(Object sender, Report report);
|
||||
|
||||
/**
|
||||
* Prints a detailed error report about an unhandled exception.
|
||||
* @param sender - the object containing the caller method.
|
||||
* @param reportBuilder - an error report builder that will be used to get the report.
|
||||
*/
|
||||
void reportDetailed(Object sender, ReportBuilder reportBuilder);
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
package com.github.joelgodofwar.mmh.common.error;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a error or warning report.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class Report {
|
||||
private final ReportType type;
|
||||
private final Throwable exception;
|
||||
private final Object[] messageParameters;
|
||||
private final Object[] callerParameters;
|
||||
|
||||
// Used to rate limit reports that are similar
|
||||
private final long rateLimit;
|
||||
|
||||
/**
|
||||
* Must be constructed through the factory method in Report.
|
||||
*/
|
||||
public static class ReportBuilder {
|
||||
private ReportType type;
|
||||
private Throwable exception;
|
||||
private Object[] messageParameters;
|
||||
private Object[] callerParameters;
|
||||
private long rateLimit;
|
||||
|
||||
private ReportBuilder() {
|
||||
// Don't allow
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current report type. Cannot be NULL.
|
||||
* @param type - report type.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public ReportBuilder type(ReportType type) {
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Report type cannot be set to NULL.");
|
||||
}
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current exception that occurred.
|
||||
* @param exception - exception that occurred.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public ReportBuilder error(@Nullable Throwable exception) {
|
||||
this.exception = exception;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message parameters that are used to construct a message text.
|
||||
* @param messageParameters - parameters for the report type.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public ReportBuilder messageParam(@Nullable Object... messageParameters) {
|
||||
this.messageParameters = messageParameters;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameters in the caller method. This is optional.
|
||||
* @param callerParameters - parameters of the caller method.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public ReportBuilder callerParam(@Nullable Object... callerParameters) {
|
||||
this.callerParameters = callerParameters;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum number of nanoseconds to wait until a report of equal type and parameters
|
||||
* is allowed to be printed again.
|
||||
* @param rateLimit - number of nanoseconds, or 0 to disable. Cannot be negative.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public ReportBuilder rateLimit(long rateLimit) {
|
||||
if (rateLimit < 0) {
|
||||
throw new IllegalArgumentException("Rate limit cannot be less than zero.");
|
||||
}
|
||||
this.rateLimit = rateLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum time to wait until a report of equal type and parameters is allowed to be printed again.
|
||||
* @param rateLimit - the time, or 0 to disable. Cannot be negative.
|
||||
* @param rateUnit - the unit of the rate limit.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public ReportBuilder rateLimit(long rateLimit, TimeUnit rateUnit) {
|
||||
return rateLimit(TimeUnit.NANOSECONDS.convert(rateLimit, rateUnit));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new report with the provided input.
|
||||
* @return A new report.
|
||||
*/
|
||||
public Report build() {
|
||||
return new Report(type, exception, messageParameters, callerParameters, rateLimit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new report builder.
|
||||
* @param type - the initial report type.
|
||||
* @return Report builder.
|
||||
*/
|
||||
public static ReportBuilder newBuilder(ReportType type) {
|
||||
return new ReportBuilder().type(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new report with the given type and parameters.
|
||||
* @param exception - exception that occured in the caller method.
|
||||
* @param type - the report type that will be used to construct the message.
|
||||
* @param messageParameters - parameters used to construct the report message.
|
||||
* @param callerParameters - parameters from the caller method.
|
||||
*/
|
||||
protected Report(ReportType type, @Nullable Throwable exception,
|
||||
@Nullable Object[] messageParameters, @Nullable Object[] callerParameters) {
|
||||
this(type, exception, messageParameters, callerParameters, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new report with the given type and parameters.
|
||||
* @param exception - exception that occurred in the caller method.
|
||||
* @param type - the report type that will be used to construct the message.
|
||||
* @param messageParameters - parameters used to construct the report message.
|
||||
* @param callerParameters - parameters from the caller method.
|
||||
* @param rateLimit - minimum number of nanoseconds to wait until a report of equal type and parameters is allowed to be printed again.
|
||||
*/
|
||||
protected Report(ReportType type, @Nullable Throwable exception,
|
||||
@Nullable Object[] messageParameters, @Nullable Object[] callerParameters, long rateLimit) {
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("type cannot be NULL.");
|
||||
}
|
||||
this.type = type;
|
||||
this.exception = exception;
|
||||
this.messageParameters = messageParameters;
|
||||
this.callerParameters = callerParameters;
|
||||
this.rateLimit = rateLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the current report type with the provided message parameters.
|
||||
* @return The formated report message.
|
||||
*/
|
||||
public String getReportMessage() {
|
||||
return type.getMessage(messageParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the message parameters that will be used to construc the report message.
|
||||
* <p>
|
||||
* This should not be confused with the method parameters of the caller method.
|
||||
* @return Message parameters.
|
||||
*/
|
||||
public Object[] getMessageParameters() {
|
||||
return messageParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the parameters of the caller method. Optional - may be NULL.
|
||||
* @return Parameters or the caller method.
|
||||
*/
|
||||
public Object[] getCallerParameters() {
|
||||
return callerParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the report type.
|
||||
* @return Report type.
|
||||
*/
|
||||
public ReportType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the associated exception, or NULL if not found.
|
||||
* @return Associated exception, or NULL.
|
||||
*/
|
||||
public Throwable getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we have any message parameters.
|
||||
* @return TRUE if there are any message parameters, FALSE otherwise.
|
||||
*/
|
||||
public boolean hasMessageParameters() {
|
||||
return (messageParameters != null) && (messageParameters.length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we have any caller parameters.
|
||||
* @return TRUE if there are any caller parameters, FALSE otherwise.
|
||||
*/
|
||||
public boolean hasCallerParameters() {
|
||||
return (callerParameters != null) && (callerParameters.length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve desired minimum number of nanoseconds until a report of the same type and parameters should be reprinted.
|
||||
* <p>
|
||||
* Note that this may be ignored or modified by the error reporter. Zero indicates no rate limit.
|
||||
* @return The number of nanoseconds. Never negative.
|
||||
*/
|
||||
public long getRateLimit() {
|
||||
return rateLimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = (prime * result) + Arrays.hashCode(callerParameters);
|
||||
result = (prime * result) + Arrays.hashCode(messageParameters);
|
||||
result = (prime * result) + ((type == null) ? 0 : type.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof Report) {
|
||||
Report other = (Report) obj;
|
||||
return (type == other.type) &&
|
||||
Arrays.equals(callerParameters, other.callerParameters) &&
|
||||
Arrays.equals(messageParameters, other.messageParameters);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package com.github.joelgodofwar.mmh.common.error;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.github.joelgodofwar.mmh.common.reflect.FieldAccessException;
|
||||
import com.github.joelgodofwar.mmh.common.reflect.FuzzyReflection;
|
||||
import com.github.joelgodofwar.mmh.common.reflect.fuzzy.FuzzyFieldContract;
|
||||
|
||||
/**
|
||||
* Represents a strongly-typed report. Subclasses should be immutable.
|
||||
* <p>
|
||||
* By convention, a report must be declared as a static field publicly accessible from the sender class.
|
||||
* @author Kristian
|
||||
*/
|
||||
public class ReportType {
|
||||
private final String errorFormat;
|
||||
|
||||
// Used to store the report name
|
||||
protected String reportName;
|
||||
|
||||
/**
|
||||
* Construct a new report type.
|
||||
* @param errorFormat - string used to format the underlying report.
|
||||
*/
|
||||
public ReportType(String errorFormat) {
|
||||
this.errorFormat = errorFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given report to a string, using the provided parameters.
|
||||
* @param parameters - parameters to insert, or NULL to insert nothing.
|
||||
* @return The full report in string format.
|
||||
*/
|
||||
public String getMessage(Object[] parameters) {
|
||||
if ((parameters == null) || (parameters.length == 0)) {
|
||||
return toString();
|
||||
} else {
|
||||
return String.format(errorFormat, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return errorFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the class of the given sender.
|
||||
* <p>
|
||||
* If the sender is already a Class, we return it.
|
||||
* @param sender - the sender to look up.
|
||||
* @return The class of the sender.
|
||||
*/
|
||||
public static Class<?> getSenderClass(Object sender) {
|
||||
if (sender == null) {
|
||||
throw new IllegalArgumentException("sender cannot be null.");
|
||||
} else if (sender instanceof Class<?>) {
|
||||
return (Class<?>) sender;
|
||||
} else {
|
||||
return sender.getClass();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the full canonical name of a given report type.
|
||||
* <p>
|
||||
* Note that the sender may be a class (for static callers), in which
|
||||
* case it will be used directly instead of its getClass() method.
|
||||
* <p>
|
||||
* It is thus not advisable for class classes to report reports.
|
||||
* @param sender - the sender, or its class.
|
||||
* @param type - the report type.
|
||||
* @return The full canonical name.
|
||||
*/
|
||||
public static String getReportName(Object sender, ReportType type) {
|
||||
if (sender == null) {
|
||||
throw new IllegalArgumentException("sender cannot be null.");
|
||||
}
|
||||
return getReportName(getSenderClass(sender), type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the full canonical name of a given report type.
|
||||
* <p>
|
||||
* This is in the format <i>canonical_name_of_class#report_type</i>
|
||||
* @param sender - the sender class.
|
||||
* @param type - the report instance.
|
||||
* @return The full canonical name.
|
||||
*/
|
||||
private static String getReportName(Class<?> sender, ReportType type) {
|
||||
if (sender == null) {
|
||||
throw new IllegalArgumentException("sender cannot be null.");
|
||||
}
|
||||
|
||||
// Whether or not we need to retrieve the report name again
|
||||
if (type.reportName == null) {
|
||||
for (Field field : getReportFields(sender)) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
|
||||
if (field.get(null) == type) {
|
||||
// We got the right field!
|
||||
return type.reportName = field.getDeclaringClass().getCanonicalName() + "#" + field.getName();
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new FieldAccessException("Unable to read field " + field, e);
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Cannot find report name for " + type);
|
||||
}
|
||||
return type.reportName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all publicly associated reports.
|
||||
* @param sender - sender class.
|
||||
* @return All associated reports.
|
||||
*/
|
||||
public static ReportType[] getReports(Class<?> sender) {
|
||||
if (sender == null) {
|
||||
throw new IllegalArgumentException("sender cannot be NULL.");
|
||||
}
|
||||
List<ReportType> result = new ArrayList<ReportType>();
|
||||
|
||||
// Go through all the fields
|
||||
for (Field field : getReportFields(sender)) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
result.add((ReportType) field.get(null));
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new FieldAccessException("Unable to read field " + field, e);
|
||||
}
|
||||
}
|
||||
return result.toArray(new ReportType[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all publicly associated report fields.
|
||||
* @param clazz - sender class.
|
||||
* @return All associated report fields.
|
||||
*/
|
||||
private static List<Field> getReportFields(Class<?> clazz) {
|
||||
return FuzzyReflection.fromClass(clazz, true)
|
||||
.getFieldList(FuzzyFieldContract.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.typeDerivedOf(ReportType.class)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
public class ExactReflection {
|
||||
|
||||
private static final Joiner COMMA_SEPERATED_JOINER = Joiner.on(", ");
|
||||
|
||||
// The class we're actually representing
|
||||
private final Class<?> source;
|
||||
private final boolean forceAccess;
|
||||
|
||||
private ExactReflection(Class<?> source, boolean forceAccess) {
|
||||
this.source = Preconditions.checkNotNull(source, "source class cannot be NULL");
|
||||
this.forceAccess = forceAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an exact reflection instance from a given class.
|
||||
*
|
||||
* @param source - the class we'll use.
|
||||
* @param forceAccess - whether to also search for members which are out of the allowed scope.
|
||||
* @return A fuzzy reflection instance.
|
||||
*/
|
||||
public static ExactReflection fromClass(Class<?> source, boolean forceAccess) {
|
||||
return new ExactReflection(source, forceAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an exact reflection instance from an object.
|
||||
*
|
||||
* @param reference - the object we'll use.
|
||||
* @param forceAccess - whether to also search for members which are out of the allowed scope.
|
||||
* @return A fuzzy reflection instance that uses the class of the given object.
|
||||
*/
|
||||
public static ExactReflection fromObject(Object reference, boolean forceAccess) {
|
||||
return new ExactReflection(reference.getClass(), forceAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the first method in the class hierarchy with the given name and parameters.
|
||||
* <p>
|
||||
* If {@link #isForceAccess()} is TRUE, we will also search for methods which are out of the caller scope.
|
||||
*
|
||||
* @param methodName - the name of the method to find, NULL to only search by using the given parameters.
|
||||
* @param parameters - the parameters of the method to find.
|
||||
* @return the first matching method.
|
||||
* @throws IllegalArgumentException if there is no method with the given name and parameter types.
|
||||
*/
|
||||
public Method getMethod(String methodName, Class<?>... parameters) {
|
||||
Method method = this.lookupMethod(this.source, methodName, parameters);
|
||||
if (method == null) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find method %s(%s) in %s",
|
||||
methodName,
|
||||
COMMA_SEPERATED_JOINER.join(parameters),
|
||||
this.source.getName()));
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first method in the class hierarchy with the given name and parameters.
|
||||
* <p>
|
||||
* If {@link #isForceAccess()} is TRUE, we will also search for methods which are out of the caller scope.
|
||||
*
|
||||
* @param methodName - the name of the method to find, NULL to only search by using the given parameters.
|
||||
* @param parameters - the parameters of the method to find.
|
||||
* @return the first matching method, NULL if no method matches.
|
||||
*/
|
||||
public Method findMethod(String methodName, Class<?>... parameters) {
|
||||
return this.lookupMethod(this.source, methodName, parameters);
|
||||
}
|
||||
|
||||
// For recursion
|
||||
private Method lookupMethod(Class<?> instanceClass, String methodName, Class<?>... parameters) {
|
||||
for (Method method : instanceClass.getDeclaredMethods()) {
|
||||
if ((this.forceAccess || Modifier.isPublic(method.getModifiers()))
|
||||
&& ((methodName == null) || method.getName().equals(methodName))
|
||||
&& Arrays.equals(method.getParameterTypes(), parameters)) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
// Search in every superclass
|
||||
if (instanceClass.getSuperclass() != null) {
|
||||
return this.lookupMethod(instanceClass.getSuperclass(), methodName, parameters);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field in the class hierarchy by the given name.
|
||||
* <p>
|
||||
* If {@link #isForceAccess()} is TRUE, we will also search for fields which are out of the caller scope.
|
||||
*
|
||||
* @param fieldName - the name of the field to find.
|
||||
* @return the first matching field.
|
||||
* @throws IllegalArgumentException if no field with the given name was found.
|
||||
*/
|
||||
public Field getField(String fieldName) {
|
||||
Field field = this.lookupField(this.source, fieldName);
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find field with name %s in %s.",
|
||||
fieldName,
|
||||
this.source.getName()));
|
||||
}
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a field in the class hierarchy by the given name.
|
||||
* <p>
|
||||
* If {@link #isForceAccess()} is TRUE, we will also search for fields which are out of the caller scope.
|
||||
*
|
||||
* @param fieldName - the name of the field to find.
|
||||
* @return the first matching field, null if no field matches.
|
||||
*/
|
||||
public Field findField(String fieldName) {
|
||||
return this.lookupField(this.source, fieldName);
|
||||
}
|
||||
|
||||
// For recursion
|
||||
private Field lookupField(Class<?> instanceClass, String fieldName) {
|
||||
for (Field field : instanceClass.getDeclaredFields()) {
|
||||
if ((this.forceAccess || Modifier.isPublic(field.getModifiers())) && field.getName().equals(fieldName)) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively find the correct field
|
||||
if (instanceClass.getSuperclass() != null) {
|
||||
return this.lookupField(instanceClass.getSuperclass(), fieldName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the first constructor in the class hierarchy with the given parameters.
|
||||
* <p>
|
||||
* If {@link #isForceAccess()} is TRUE, we will also search for constructors which are out of the caller scope.
|
||||
*
|
||||
* @param parameters - the parameters of the constructor to find.
|
||||
* @return the first matching constructor.
|
||||
* @throws IllegalArgumentException if no constructor with the given parameters was found.
|
||||
*/
|
||||
public Constructor<?> getConstructor(Class<?>... parameters) {
|
||||
Constructor<?> constructor = this.findConstructor(parameters);
|
||||
if (constructor == null) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find constructor (%s) in %s",
|
||||
COMMA_SEPERATED_JOINER.join(parameters),
|
||||
this.source.getName()));
|
||||
}
|
||||
|
||||
return constructor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first constructor in the class hierarchy with the given parameters.
|
||||
* <p>
|
||||
* If {@link #isForceAccess()} is TRUE, we will also search for constructors which are out of the caller scope.
|
||||
*
|
||||
* @param parameters - the parameters of the constructor to find.
|
||||
* @return the first matching constructor, NULL if no constructor matches.
|
||||
*/
|
||||
public Constructor<?> findConstructor(Class<?>... parameters) {
|
||||
try {
|
||||
Constructor<?> constructor = this.source.getDeclaredConstructor(parameters);
|
||||
return this.forceAccess || Modifier.isPublic(constructor.getModifiers()) ? constructor : null;
|
||||
} catch (NoSuchMethodException exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an {@link ExactReflection} object where scope restrictions are ignored.
|
||||
*
|
||||
* @return A copy of the current object.
|
||||
*/
|
||||
public ExactReflection forceAccess() {
|
||||
return new ExactReflection(this.source, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we are overriding scope restrictions and will also find private, protected or package members.
|
||||
*
|
||||
* @return TRUE if we are, FALSE otherwise.
|
||||
*/
|
||||
public boolean isForceAccess() {
|
||||
return this.forceAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the source class we are searching.
|
||||
*
|
||||
* @return The source.
|
||||
*/
|
||||
public Class<?> getSource() {
|
||||
return this.source;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.github.joelgodofwar.mmh.common.reflect;
|
||||
|
||||
/**
|
||||
* Invoked when a field is inaccessible due to security limitations, or when it simply doesn't exist.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class FieldAccessException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Generated by Eclipse.
|
||||
*/
|
||||
private static final long serialVersionUID = 1911011681494034617L;
|
||||
|
||||
public FieldAccessException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public FieldAccessException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public FieldAccessException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public FieldAccessException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public static FieldAccessException fromFormat(String message, Object... params) {
|
||||
return new FieldAccessException(String.format(message, params));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String message = getMessage();
|
||||
return "FieldAccessException" + (message != null ? ": " + message : "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,597 @@
|
||||
/*
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.github.joelgodofwar.mmh.common.reflect;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.github.joelgodofwar.mmh.common.reflect.accessors.Accessors;
|
||||
import com.github.joelgodofwar.mmh.common.reflect.fuzzy.AbstractFuzzyMatcher;
|
||||
import com.github.joelgodofwar.mmh.common.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.github.joelgodofwar.mmh.common.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* Retrieves fields and methods by signature, not just name.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class FuzzyReflection {
|
||||
|
||||
private static final Joiner COMMA_JOINER = Joiner.on(", ");
|
||||
|
||||
// The class we're actually representing
|
||||
private final Class<?> source;
|
||||
private final boolean forceAccess;
|
||||
|
||||
public FuzzyReflection(Class<?> source, boolean forceAccess) {
|
||||
this.source = source;
|
||||
this.forceAccess = forceAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a fuzzy reflection instance from a given class.
|
||||
*
|
||||
* @param source - the class we'll use.
|
||||
* @return A fuzzy reflection instance.
|
||||
*/
|
||||
public static FuzzyReflection fromClass(Class<?> source) {
|
||||
return fromClass(source, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a fuzzy reflection instance from a given class.
|
||||
*
|
||||
* @param source - the class we'll use.
|
||||
* @param forceAccess - whether to override scope restrictions.
|
||||
* @return A fuzzy reflection instance.
|
||||
*/
|
||||
public static FuzzyReflection fromClass(Class<?> source, boolean forceAccess) {
|
||||
return new FuzzyReflection(source, forceAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a fuzzy reflection instance from an object.
|
||||
*
|
||||
* @param reference - the object we'll use.
|
||||
* @return A fuzzy reflection instance that uses the class of the given object.
|
||||
*/
|
||||
public static FuzzyReflection fromObject(Object reference) {
|
||||
return new FuzzyReflection(reference.getClass(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a fuzzy reflection instance from an object.
|
||||
*
|
||||
* @param reference - the object we'll use.
|
||||
* @param forceAccess - whether to override scope restrictions.
|
||||
* @return A fuzzy reflection instance that uses the class of the given object.
|
||||
*/
|
||||
public static FuzzyReflection fromObject(Object reference, boolean forceAccess) {
|
||||
return new FuzzyReflection(reference.getClass(), forceAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value of the first field of the given type.
|
||||
*
|
||||
* @param <T> Type
|
||||
* @param instance - the instance to retrieve from.
|
||||
* @param fieldClass - type of the field to retrieve.
|
||||
* @param forceAccess - whether to look for private and protected fields.
|
||||
* @return The value of that field.
|
||||
* @throws IllegalArgumentException If the field cannot be found.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getFieldValue(Object instance, Class<T> fieldClass, boolean forceAccess) {
|
||||
return (T) Accessors.getFieldAccessor(instance.getClass(), fieldClass, forceAccess).get(instance);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <T> Set<T> combineArrays(T[]... arrays) {
|
||||
Set<T> result = new LinkedHashSet<>();
|
||||
for (T[] elements : arrays) {
|
||||
if (elements != null) {
|
||||
Collections.addAll(result, elements);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the underlying class.
|
||||
*
|
||||
* @return The underlying class.
|
||||
*/
|
||||
public Class<?> getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves whether or not not to override any scope restrictions.
|
||||
*
|
||||
* @return TRUE if we override scope, FALSE otherwise.
|
||||
*/
|
||||
public boolean isForceAccess() {
|
||||
return this.forceAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the singleton instance of a class, from a method or field.
|
||||
*
|
||||
* @return The singleton instance.
|
||||
* @throws IllegalStateException If the class has no singleton.
|
||||
*/
|
||||
public Object getSingleton() {
|
||||
try {
|
||||
// try a no-args method which is static and returns the same type as the target class
|
||||
Method method = this.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.parameterCount(0)
|
||||
.returnDerivedOf(this.source)
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.build());
|
||||
return Accessors.getMethodAccessor(method).invoke(null);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// that method doesn't exist...
|
||||
}
|
||||
|
||||
try {
|
||||
// try a field which is static and of the same type as the target class
|
||||
Field field = this.getField(FuzzyFieldContract.newBuilder()
|
||||
.typeDerivedOf(this.source)
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.build());
|
||||
return Accessors.getFieldAccessor(field).get(null);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// that field doesn't exist
|
||||
}
|
||||
|
||||
// we're unable to find the field
|
||||
throw new IllegalStateException("Unable to retrieve singleton instance of " + this.source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the first method that matches.
|
||||
* <p>
|
||||
* ForceAccess must be TRUE in order for this method to access private, protected and package level method.
|
||||
*
|
||||
* @param matcher - the matcher to use.
|
||||
* @return The first method that satisfies the given matcher.
|
||||
* @throws IllegalArgumentException If the method cannot be found.
|
||||
*/
|
||||
public Method getMethod(AbstractFuzzyMatcher<MethodInfo> matcher) {
|
||||
List<Method> result = this.getMethodList(matcher);
|
||||
if (result.size() > 0) {
|
||||
return result.get(0);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unable to find a method that matches " + matcher);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a method that matches. If there are multiple methods that match, the first one with the preferred name is
|
||||
* selected.
|
||||
* <p>
|
||||
* ForceAccess must be TRUE in order for this method to access private, protected and package level method.
|
||||
*
|
||||
* @param matcher - the matcher to use.
|
||||
* @param preferred - the preferred name, null for no preference.
|
||||
* @return The first method that satisfies the given matcher.
|
||||
* @throws IllegalArgumentException If the method cannot be found.
|
||||
*/
|
||||
public Method getMethod(AbstractFuzzyMatcher<MethodInfo> matcher, String preferred) {
|
||||
List<Method> result = this.getMethodList(matcher);
|
||||
|
||||
// if we got more than one result check for the preferred method name
|
||||
if ((result.size() > 1) && (preferred != null)) {
|
||||
for (Method method : result) {
|
||||
if (method.getName().equals(preferred)) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.size() > 0) {
|
||||
return result.get(0);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unable to find a method that matches " + matcher);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a method by looking at its name.
|
||||
*
|
||||
* @param nameRegex - regular expression that will match method names.
|
||||
* @return The first method that satisfies the regular expression.
|
||||
* @throws IllegalArgumentException If the method cannot be found.
|
||||
*/
|
||||
public Method getMethodByName(String nameRegex) {
|
||||
// compile the regex only once
|
||||
Pattern match = Pattern.compile(nameRegex);
|
||||
for (Method method : this.getMethods()) {
|
||||
if (match.matcher(method.getName()).matches()) {
|
||||
// Right - this is probably it.
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find a method in %s that matches \"%s\"",
|
||||
this.source,
|
||||
nameRegex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a method by looking at the parameter types only.
|
||||
*
|
||||
* @param name - potential name of the method. Only used by the error mechanism.
|
||||
* @param args - parameter types of the method to find.
|
||||
* @return The first method that satisfies the parameter types.
|
||||
* @throws IllegalArgumentException If the method cannot be found.
|
||||
*/
|
||||
public Method getMethodByParameters(String name, Class<?>... args) {
|
||||
// Find the correct method to call
|
||||
for (Method method : this.getMethods()) {
|
||||
if (Arrays.equals(method.getParameterTypes(), args)) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
// That sucks
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find %s(%s) in %s",
|
||||
name,
|
||||
COMMA_JOINER.join(args),
|
||||
this.source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a method by looking at the parameter types and return type only.
|
||||
*
|
||||
* @param name - potential name of the method. Only used by the error mechanism.
|
||||
* @param returnType - return type of the method to find.
|
||||
* @param args - parameter types of the method to find.
|
||||
* @return The first method that satisfies the parameter types.
|
||||
* @throws IllegalArgumentException If the method cannot be found.
|
||||
*/
|
||||
public Method getMethodByReturnTypeAndParameters(String name, Class<?> returnType, Class<?>... args) {
|
||||
// Find the correct method to call
|
||||
List<Method> methods = this.getMethodListByParameters(returnType, args);
|
||||
if (methods.size() > 0) {
|
||||
return methods.get(0);
|
||||
} else {
|
||||
// That sucks
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find %s(%s): %s in %s",
|
||||
name,
|
||||
COMMA_JOINER.join(args),
|
||||
returnType,
|
||||
this.source));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of every method that matches the given matcher.
|
||||
* <p>
|
||||
* ForceAccess must be TRUE in order for this method to access private, protected and package level methods.
|
||||
*
|
||||
* @param matcher - the matcher to apply.
|
||||
* @return List of found methods.
|
||||
*/
|
||||
public List<Method> getMethodList(AbstractFuzzyMatcher<MethodInfo> matcher) {
|
||||
// finds and adds all matching methods
|
||||
List<Method> methods = new ArrayList<>();
|
||||
for (Method method : this.getMethods()) {
|
||||
if (matcher.isMatch(MethodInfo.fromMethod(method), this.source)) {
|
||||
methods.add(method);
|
||||
}
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves every method that has the given parameter types and return type.
|
||||
*
|
||||
* @param returnType - return type of the method to find.
|
||||
* @param args - parameter types of the method to find.
|
||||
* @return Every method that satisfies the given constraints.
|
||||
*/
|
||||
public List<Method> getMethodListByParameters(Class<?> returnType, Class<?>... args) {
|
||||
List<Method> methods = new ArrayList<>();
|
||||
// Find the correct method to call
|
||||
for (Method method : this.getMethods()) {
|
||||
if (method.getReturnType().equals(returnType) && Arrays.equals(method.getParameterTypes(), args)) {
|
||||
methods.add(method);
|
||||
}
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the first field that matches.
|
||||
* <p>
|
||||
* ForceAccess must be TRUE in order for this method to access private, protected and package level fields.
|
||||
*
|
||||
* @param matcher - the matcher to use.
|
||||
* @return The first method that satisfies the given matcher.
|
||||
* @throws IllegalArgumentException If the method cannot be found.
|
||||
*/
|
||||
public Field getField(AbstractFuzzyMatcher<Field> matcher) {
|
||||
List<Field> result = this.getFieldList(matcher);
|
||||
if (result.size() > 0) {
|
||||
return result.get(0);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unable to find a field that matches " + matcher);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a field by name.
|
||||
*
|
||||
* @param nameRegex - regular expression that will match a field name.
|
||||
* @return The first field to match the given expression.
|
||||
* @throws IllegalArgumentException If the field cannot be found.
|
||||
*/
|
||||
public Field getFieldByName(String nameRegex) {
|
||||
// compile the pattern only once
|
||||
Pattern match = Pattern.compile(nameRegex);
|
||||
for (Field field : this.getFields()) {
|
||||
if (match.matcher(field.getName()).matches()) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
// Looks like we're outdated. Too bad.
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find a field with a name matching \"%s\" in %s",
|
||||
nameRegex,
|
||||
this.source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the first field with a type equal to or more specific to the given type.
|
||||
*
|
||||
* @param name - name the field probably is given. This will only be used in the error message.
|
||||
* @param type - type of the field to find.
|
||||
* @return The first field with a type that is an instance of the given type.
|
||||
*/
|
||||
public Field getFieldByType(String name, Class<?> type) {
|
||||
List<Field> fields = this.getFieldListByType(type);
|
||||
if (fields.size() > 0) {
|
||||
return fields.get(0);
|
||||
} else {
|
||||
// Looks like we're outdated. Too bad.
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find a field \"%s\" with the type %s in %s",
|
||||
name,
|
||||
type,
|
||||
this.source));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves every field with a type equal to or more specific to the given type.
|
||||
*
|
||||
* @param type - type of the fields to find.
|
||||
* @return Every field with a type that is an instance of the given type.
|
||||
*/
|
||||
public List<Field> getFieldListByType(Class<?> type) {
|
||||
// Field with a compatible type
|
||||
List<Field> fields = new ArrayList<>();
|
||||
for (Field field : this.getFields()) {
|
||||
if (type.isAssignableFrom(field.getType())) {
|
||||
fields.add(field);
|
||||
}
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a field with a given type and parameters. This is most useful when dealing with Collections.
|
||||
*
|
||||
* @param fieldType Type of the field
|
||||
* @param params Variable length array of type parameters
|
||||
* @return The field
|
||||
* @throws IllegalArgumentException If the field cannot be found
|
||||
*/
|
||||
public Field getParameterizedField(Class<?> fieldType, Class<?>... params) {
|
||||
for (Field field : this.getFields()) {
|
||||
if (field.getType().equals(fieldType)) {
|
||||
Type type = field.getGenericType();
|
||||
if (type instanceof ParameterizedType) {
|
||||
if (Arrays.equals(((ParameterizedType) type).getActualTypeArguments(), params)) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find a field of type %s<%s> in %s",
|
||||
fieldType,
|
||||
COMMA_JOINER.join(params),
|
||||
this.source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of every field that matches the given matcher.
|
||||
* <p>
|
||||
* ForceAccess must be TRUE in order for this method to access private, protected and package level fields.
|
||||
*
|
||||
* @param matcher - the matcher to apply.
|
||||
* @return List of found fields.
|
||||
*/
|
||||
public List<Field> getFieldList(AbstractFuzzyMatcher<Field> matcher) {
|
||||
// Add all matching fields to the list
|
||||
List<Field> fields = new ArrayList<>();
|
||||
for (Field field : this.getFields()) {
|
||||
if (matcher.isMatch(field, this.source)) {
|
||||
fields.add(field);
|
||||
}
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a field by type.
|
||||
* <p>
|
||||
* Note that the type is matched using the full canonical representation, i.e.:
|
||||
* <ul>
|
||||
* <li>java.util.List</li>
|
||||
* <li>net.comphenix.xp.ExperienceMod</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param typeRegex - regular expression that will match the field type.
|
||||
* @return The first field with a type that matches the given regular expression.
|
||||
* @throws IllegalArgumentException If the field cannot be found.
|
||||
*/
|
||||
public Field getFieldByType(String typeRegex) {
|
||||
Pattern match = Pattern.compile(typeRegex);
|
||||
|
||||
// Like above, only here we test the field type
|
||||
for (Field field : this.getFields()) {
|
||||
String name = field.getType().getName();
|
||||
if (match.matcher(name).matches()) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
// Looks like we're outdated. Too bad.
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find a field with a type that matches \"%s\" in %s",
|
||||
typeRegex,
|
||||
this.source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the first constructor that matches.
|
||||
* <p>
|
||||
* ForceAccess must be TRUE in order for this method to access private, protected and package level constructors.
|
||||
*
|
||||
* @param matcher - the matcher to use.
|
||||
* @return The first constructor that satisfies the given matcher.
|
||||
* @throws IllegalArgumentException If the constructor cannot be found.
|
||||
*/
|
||||
public Constructor<?> getConstructor(AbstractFuzzyMatcher<MethodInfo> matcher) {
|
||||
List<Constructor<?>> result = this.getConstructorList(matcher);
|
||||
if (result.size() > 0) {
|
||||
return result.get(0);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unable to find a method that matches " + matcher);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of every constructor that matches the given matcher.
|
||||
* <p>
|
||||
* ForceAccess must be TRUE in order for this method to access private, protected and package level constructors.
|
||||
*
|
||||
* @param matcher - the matcher to apply.
|
||||
* @return List of found constructors.
|
||||
*/
|
||||
public List<Constructor<?>> getConstructorList(AbstractFuzzyMatcher<MethodInfo> matcher) {
|
||||
// Add all matching constructors to the list
|
||||
List<Constructor<?>> constructors = new ArrayList<>();
|
||||
for (Constructor<?> constructor : this.getConstructors()) {
|
||||
if (matcher.isMatch(MethodInfo.fromConstructor(constructor), this.source)) {
|
||||
constructors.add(constructor);
|
||||
}
|
||||
}
|
||||
|
||||
return constructors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all private and public fields in declared order.
|
||||
* <p>
|
||||
* Private, protected and package fields are ignored if forceAccess is FALSE.
|
||||
*
|
||||
* @return Every field.
|
||||
*/
|
||||
public Set<Field> getFields() {
|
||||
if (this.forceAccess) {
|
||||
return combineArrays(this.source.getDeclaredFields(), this.source.getFields());
|
||||
} else {
|
||||
return combineArrays(this.source.getFields());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all private and public fields, up until a certain superclass.
|
||||
*
|
||||
* @param excludeClass - the class (and its superclasses) to exclude from the search.
|
||||
* @return Every such declared field.
|
||||
*/
|
||||
public Set<Field> getDeclaredFields(Class<?> excludeClass) {
|
||||
// we only need to do this if we include inherited fields
|
||||
if (this.forceAccess) {
|
||||
Class<?> current = this.source;
|
||||
Set<Field> fields = Sets.newLinkedHashSet();
|
||||
|
||||
while ((current != null) && (current != excludeClass)) {
|
||||
fields.addAll(Arrays.asList(current.getDeclaredFields()));
|
||||
current = current.getSuperclass();
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
return this.getFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all private and public methods in declared order (after JDK 1.5).
|
||||
* <p>
|
||||
* Private, protected and package methods are ignored if forceAccess is FALSE.
|
||||
*
|
||||
* @return Every method.
|
||||
*/
|
||||
public Set<Method> getMethods() {
|
||||
if (this.forceAccess) {
|
||||
return combineArrays(this.source.getDeclaredMethods(), this.source.getMethods());
|
||||
} else {
|
||||
return combineArrays(this.source.getMethods());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all private and public constructors in declared order (after JDK 1.5).
|
||||
* <p>
|
||||
* Private, protected and package constructors are ignored if forceAccess is FALSE.
|
||||
*
|
||||
* @return Every constructor.
|
||||
*/
|
||||
public Set<Constructor<?>> getConstructors() {
|
||||
return combineArrays(this.forceAccess ? this.source.getDeclaredConstructors() : this.source.getConstructors());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.GenericDeclaration;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* Represents a method or a constructor.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public abstract class MethodInfo implements GenericDeclaration, Member {
|
||||
|
||||
/**
|
||||
* Wraps a method as a MethodInfo object.
|
||||
*
|
||||
* @param method - the method to wrap.
|
||||
* @return The wrapped method.
|
||||
*/
|
||||
public static MethodInfo fromMethod(final Method method) {
|
||||
return new MethodInfo() {
|
||||
@Override
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
|
||||
return method.getAnnotation(annotationClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
return method.getAnnotations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation[] getDeclaredAnnotations() {
|
||||
return method.getDeclaredAnnotations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return method.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getParameterTypes() {
|
||||
return method.getParameterTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getDeclaringClass() {
|
||||
return method.getDeclaringClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnType() {
|
||||
return method.getReturnType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getModifiers() {
|
||||
return method.getModifiers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getExceptionTypes() {
|
||||
return method.getExceptionTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeVariable<?>[] getTypeParameters() {
|
||||
return method.getTypeParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toGenericString() {
|
||||
return method.toGenericString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return method.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSynthetic() {
|
||||
return method.isSynthetic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return method.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstructor() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a list of method infos from a given array of methods.
|
||||
*
|
||||
* @param methods - array of methods.
|
||||
* @return Method info list.
|
||||
*/
|
||||
public static Collection<MethodInfo> fromMethods(Method[] methods) {
|
||||
return fromMethods(Arrays.asList(methods));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a list of method infos from a given collection of methods.
|
||||
*
|
||||
* @param methods - list of methods.
|
||||
* @return Method info list.
|
||||
*/
|
||||
public static List<MethodInfo> fromMethods(Collection<Method> methods) {
|
||||
List<MethodInfo> infos = Lists.newArrayList();
|
||||
for (Method method : methods) {
|
||||
infos.add(fromMethod(method));
|
||||
}
|
||||
|
||||
return infos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a constructor as a method information object.
|
||||
*
|
||||
* @param constructor - the constructor to wrap.
|
||||
* @return A wrapped constructor.
|
||||
*/
|
||||
public static MethodInfo fromConstructor(final Constructor<?> constructor) {
|
||||
return new MethodInfo() {
|
||||
@Override
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
|
||||
return constructor.getAnnotation(annotationClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
return constructor.getAnnotations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation[] getDeclaredAnnotations() {
|
||||
return constructor.getDeclaredAnnotations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return constructor.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getParameterTypes() {
|
||||
return constructor.getParameterTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getDeclaringClass() {
|
||||
return constructor.getDeclaringClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getReturnType() {
|
||||
return Void.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getModifiers() {
|
||||
return constructor.getModifiers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getExceptionTypes() {
|
||||
return constructor.getExceptionTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeVariable<?>[] getTypeParameters() {
|
||||
return constructor.getTypeParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toGenericString() {
|
||||
return constructor.toGenericString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return constructor.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSynthetic() {
|
||||
return constructor.isSynthetic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return constructor.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstructor() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a list of method infos from a given array of constructors.
|
||||
*
|
||||
* @param constructors - array of constructors.
|
||||
* @return Method info list.
|
||||
*/
|
||||
public static Collection<MethodInfo> fromConstructors(Constructor<?>[] constructors) {
|
||||
return fromConstructors(Arrays.asList(constructors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a list of method infos from a given collection of constructors.
|
||||
*
|
||||
* @param constructors - list of constructors.
|
||||
* @return Method info list.
|
||||
*/
|
||||
public static List<MethodInfo> fromConstructors(Collection<Constructor<?>> constructors) {
|
||||
List<MethodInfo> infos = Lists.newArrayList();
|
||||
|
||||
for (Constructor<?> constructor : constructors) {
|
||||
infos.add(fromConstructor(constructor));
|
||||
}
|
||||
return infos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string describing this method or constructor
|
||||
*
|
||||
* @return A string representation of the object.
|
||||
* @see Method#toString()
|
||||
* @see Constructor#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string describing this method or constructor, including type parameters.
|
||||
*
|
||||
* @return A string describing this Method, include type parameters
|
||||
* @see Method#toGenericString()
|
||||
* @see Constructor#toGenericString()
|
||||
*/
|
||||
public abstract String toGenericString();
|
||||
|
||||
/**
|
||||
* Returns an array of Class objects that represent the types of the exceptions declared to be thrown by the
|
||||
* underlying method or constructor represented by this MethodInfo object.
|
||||
*
|
||||
* @return The exception types declared as being thrown by the method or constructor this object represents.
|
||||
* @see Method#getExceptionTypes()
|
||||
* @see Constructor#getExceptionTypes()
|
||||
*/
|
||||
public abstract Class<?>[] getExceptionTypes();
|
||||
|
||||
/**
|
||||
* Returns a Class object that represents the formal return type of the method or constructor represented by this
|
||||
* MethodInfo object.
|
||||
* <p>
|
||||
* This is always {@link Void} for constructors.
|
||||
*
|
||||
* @return The return value, or Void if a constructor.
|
||||
* @see Method#getReturnType()
|
||||
*/
|
||||
public abstract Class<?> getReturnType();
|
||||
|
||||
/**
|
||||
* Returns an array of Class objects that represent the formal parameter types, in declaration order, of the method or
|
||||
* constructor represented by this MethodInfo object.
|
||||
*
|
||||
* @return The parameter types for the method or constructor this object represents.
|
||||
* @see Method#getParameterTypes()
|
||||
* @see Constructor#getParameterTypes()
|
||||
*/
|
||||
public abstract Class<?>[] getParameterTypes();
|
||||
|
||||
/**
|
||||
* Determine if this is a constructor or not.
|
||||
*
|
||||
* @return TRUE if this represents a constructor, FALSE otherwise.
|
||||
*/
|
||||
public abstract boolean isConstructor();
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.github.joelgodofwar.mmh.common.reflect.accessors.Accessors;
|
||||
import com.google.common.primitives.Primitives;
|
||||
|
||||
/**
|
||||
* Used to print the content of an arbitrary class.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class PrettyPrinter {
|
||||
|
||||
/**
|
||||
* How far we will recurse.
|
||||
*/
|
||||
public static final int RECURSE_DEPTH = 3;
|
||||
|
||||
/**
|
||||
* Print the contents of an object.
|
||||
*
|
||||
* @param object - the object to serialize.
|
||||
* @return String representation of the class.
|
||||
* @throws IllegalAccessException If the object is null
|
||||
*/
|
||||
public static String printObject(Object object) throws IllegalAccessException {
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException("object cannot be NULL.");
|
||||
}
|
||||
|
||||
return printObject(object, object.getClass(), Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the contents of an object.
|
||||
*
|
||||
* @param object - the object to serialize.
|
||||
* @param start - class to start at.
|
||||
* @param stop - superclass that will stop the process.
|
||||
* @return String representation of the class
|
||||
* @throws IllegalAccessException If the object is null
|
||||
*/
|
||||
public static String printObject(Object object, Class<?> start, Class<?> stop) throws IllegalAccessException {
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException("object cannot be NULL.");
|
||||
}
|
||||
|
||||
return printObject(object, start, stop, RECURSE_DEPTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the contents of an object.
|
||||
*
|
||||
* @param object - the object to serialize.
|
||||
* @param start - class to start at.
|
||||
* @param stop - superclass that will stop the process.
|
||||
* @param hierachyDepth - maximum recursion level.
|
||||
* @return String representation of the class.
|
||||
* @throws IllegalAccessException If the object is null
|
||||
*/
|
||||
public static String printObject(Object object, Class<?> start, Class<?> stop, int hierachyDepth)
|
||||
throws IllegalAccessException {
|
||||
return printObject(object, start, stop, hierachyDepth, ObjectPrinter.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the contents of an object.
|
||||
*
|
||||
* @param object - the object to serialize.
|
||||
* @param start - class to start at.
|
||||
* @param stop - superclass that will stop the process.
|
||||
* @param hierachyDepth - maximum recursion level.
|
||||
* @param printer - a generic object printer.
|
||||
* @return String representation of the class.
|
||||
* @throws IllegalAccessException If the object is null
|
||||
*/
|
||||
public static String printObject(Object object, Class<?> start, Class<?> stop, int hierachyDepth,
|
||||
ObjectPrinter printer) throws IllegalAccessException {
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException("object cannot be NULL.");
|
||||
}
|
||||
|
||||
StringBuilder output = new StringBuilder();
|
||||
Set<Object> previous = new HashSet<>();
|
||||
|
||||
// Start and stop
|
||||
output.append("{ ");
|
||||
printObject(output, object, start, stop, previous, hierachyDepth, true, printer);
|
||||
output.append(" }");
|
||||
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static void printIterables(StringBuilder output, Iterable iterable, Class<?> stop,
|
||||
Set<Object> previous, int hierachyIndex, ObjectPrinter printer) throws IllegalAccessException {
|
||||
|
||||
boolean first = true;
|
||||
output.append("(");
|
||||
|
||||
for (Object value : iterable) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
output.append(", ");
|
||||
}
|
||||
|
||||
// Print value
|
||||
printValue(output, value, stop, previous, hierachyIndex - 1, printer);
|
||||
}
|
||||
|
||||
output.append(")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the content of a maps entries.
|
||||
*
|
||||
* @param output - the output string builder.
|
||||
* @param map - the map to print.
|
||||
* @param current - the type of this map.
|
||||
* @param stop - the class that indicates we should stop printing.
|
||||
* @param previous - previous objects printed.
|
||||
* @param hierachyIndex - hierachy index.
|
||||
* @throws IllegalAccessException If any reflection went wrong.
|
||||
*/
|
||||
private static void printMap(StringBuilder output, Map<Object, Object> map, Class<?> current, Class<?> stop,
|
||||
Set<Object> previous, int hierachyIndex, ObjectPrinter printer) throws IllegalAccessException {
|
||||
|
||||
boolean first = true;
|
||||
output.append("[");
|
||||
|
||||
for (Entry<Object, Object> entry : map.entrySet()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
output.append(", ");
|
||||
}
|
||||
|
||||
printValue(output, entry.getKey(), stop, previous, hierachyIndex - 1, printer);
|
||||
output.append(": ");
|
||||
printValue(output, entry.getValue(), stop, previous, hierachyIndex - 1, printer);
|
||||
}
|
||||
|
||||
output.append("]");
|
||||
}
|
||||
|
||||
private static void printArray(StringBuilder output, Object array, Class<?> current, Class<?> stop,
|
||||
Set<Object> previous, int hierachyIndex, ObjectPrinter printer) throws IllegalAccessException {
|
||||
|
||||
Class<?> component = current.getComponentType();
|
||||
boolean first = true;
|
||||
|
||||
if (!component.isArray()) {
|
||||
output.append(component.getName());
|
||||
}
|
||||
output.append("[");
|
||||
|
||||
for (int i = 0; i < Array.getLength(array); i++) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
output.append(", ");
|
||||
}
|
||||
|
||||
// Handle exceptions
|
||||
try {
|
||||
printValue(output, Array.get(array, i), component, stop, previous, hierachyIndex - 1, printer);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
e.printStackTrace();
|
||||
break;
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
output.append("]");
|
||||
}
|
||||
|
||||
// Internal recursion method
|
||||
private static void printObject(StringBuilder output, Object object, Class<?> current, Class<?> stop,
|
||||
Set<Object> previous, int hierachyIndex, boolean first,
|
||||
ObjectPrinter printer) throws IllegalAccessException {
|
||||
|
||||
// See if we're supposed to skip this class
|
||||
if ((current == null) || (current == Object.class) || ((stop != null) && current.equals(stop))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't iterate twice
|
||||
previous.add(object);
|
||||
|
||||
// Hard coded limit
|
||||
if (hierachyIndex < 0) {
|
||||
output.append("...");
|
||||
return;
|
||||
}
|
||||
|
||||
for (Field field : current.getDeclaredFields()) {
|
||||
int mod = field.getModifiers();
|
||||
|
||||
// Skip a good number of the fields
|
||||
if (!Modifier.isTransient(mod) && !Modifier.isStatic(mod)) {
|
||||
Class<?> type = field.getType();
|
||||
Object value = Accessors.getFieldAccessor(field).get(object);
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
output.append(", ");
|
||||
}
|
||||
|
||||
output.append(field.getName());
|
||||
output.append(" = ");
|
||||
printValue(output, value, type, stop, previous, hierachyIndex - 1, printer);
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse
|
||||
printObject(output, object, current.getSuperclass(), stop, previous, hierachyIndex, first, printer);
|
||||
}
|
||||
|
||||
private static void printValue(StringBuilder output, Object value, Class<?> stop,
|
||||
Set<Object> previous, int hierachyIndex, ObjectPrinter printer) throws IllegalAccessException {
|
||||
// Handle the NULL case
|
||||
printValue(output, value, value != null ? value.getClass() : null, stop, previous, hierachyIndex, printer);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") private static void printValue(StringBuilder output, Object value, Class<?> type,
|
||||
Class<?> stop, Set<Object> previous, int hierachyIndex,
|
||||
ObjectPrinter printer) throws IllegalAccessException {
|
||||
|
||||
// Just print primitive types
|
||||
if (printer.print(output, value)) {
|
||||
return;
|
||||
} else if (value == null) {
|
||||
output.append("NULL");
|
||||
} else if (type.isPrimitive() || Primitives.isWrapperType(type)) {
|
||||
output.append(value);
|
||||
} else if ((type == String.class) || (hierachyIndex <= 0)) {
|
||||
output.append("\"").append(value).append("\"");
|
||||
} else if (type.isArray()) {
|
||||
printArray(output, value, type, stop, previous, hierachyIndex, printer);
|
||||
} else if (Iterable.class.isAssignableFrom(type)) {
|
||||
printIterables(output, (Iterable<?>) value, stop, previous, hierachyIndex, printer);
|
||||
} else if (Map.class.isAssignableFrom(type)) {
|
||||
printMap(output, (Map<Object, Object>) value, type, stop, previous, hierachyIndex, printer);
|
||||
} else if (ClassLoader.class.isAssignableFrom(type) || previous.contains(value)) {
|
||||
// Don't print previous objects
|
||||
output.append("\"").append(value).append("\"");
|
||||
} else {
|
||||
output.append("{ ");
|
||||
printObject(output, value, value.getClass(), stop, previous, hierachyIndex, true, printer);
|
||||
output.append(" }");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a generic object printer.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public interface ObjectPrinter {
|
||||
|
||||
ObjectPrinter DEFAULT = (output, value) -> false;
|
||||
|
||||
/**
|
||||
* Print the content of the given object.
|
||||
* <p>
|
||||
* Return FALSE in order for let the default printer take over.
|
||||
*
|
||||
* @param output - where to print the output.
|
||||
* @param value - the value to print, may be NULL.
|
||||
* @return TRUE if we processed the value and added to the output, FALSE otherwise.
|
||||
*/
|
||||
boolean print(StringBuilder output, Object value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.accessors;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.github.joelgodofwar.mmh.common.reflect.ExactReflection;
|
||||
import com.github.joelgodofwar.mmh.common.reflect.FuzzyReflection;
|
||||
|
||||
// TODO: at some point we should make everything nullable to make updates easier
|
||||
|
||||
public final class Accessors {
|
||||
|
||||
// Seal this class
|
||||
private Accessors() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an accessor (in declared order) for every field of the givne type.
|
||||
*
|
||||
* @param clazz - the type of the instance to retrieve.
|
||||
* @param fieldClass - type of the field(s) to retrieve.
|
||||
* @param forceAccess - whether to look for private and protected fields.
|
||||
* @return The accessors.
|
||||
*/
|
||||
public static FieldAccessor[] getFieldAccessorArray(Class<?> clazz, Class<?> fieldClass, boolean forceAccess) {
|
||||
return FuzzyReflection.fromClass(clazz, forceAccess).getFieldListByType(fieldClass).stream()
|
||||
.map(Accessors::getFieldAccessor)
|
||||
.toArray(FieldAccessor[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an accessor for the first field of the given type.
|
||||
*
|
||||
* @param instanceClass - the type of the instance to retrieve.
|
||||
* @param fieldName - name of the field to retrieve.
|
||||
* @param forceAccess - whether to look for private and protected fields.
|
||||
* @return The value of that field.
|
||||
* @throws IllegalArgumentException If the field cannot be found.
|
||||
*/
|
||||
//public static FieldAccessor getFieldAccessor(Class<?> instanceClass, String fieldName, boolean forceAccess) {
|
||||
// return Accessors.getFieldAccessor(ExactReflection.fromClass(instanceClass, forceAccess).getField(fieldName));
|
||||
//}
|
||||
|
||||
/**
|
||||
* Retrieve an accessor for the first field of the given type.
|
||||
*
|
||||
* @param instanceClass - the type of the instance to retrieve.
|
||||
* @param fieldClass - type of the field to retrieve.
|
||||
* @param forceAccess - whether to look for private and protected fields.
|
||||
* @return The field accessor.
|
||||
* @throws IllegalArgumentException If the field cannot be found.
|
||||
*/
|
||||
public static FieldAccessor getFieldAccessor(Class<?> instanceClass, Class<?> fieldClass, boolean forceAccess) {
|
||||
// Get a field accessor
|
||||
Field field = FuzzyReflection.fromClass(instanceClass, forceAccess).getFieldByType(null, fieldClass);
|
||||
return Accessors.getFieldAccessor(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field accessor for a field with the given name and equivalent type, or NULL.
|
||||
*
|
||||
* @param clazz - the declaration class.
|
||||
* @param fieldName - the field name.
|
||||
* @param fieldType - assignable field type.
|
||||
* @return The field accessor, or NULL if not found.
|
||||
*/
|
||||
public static FieldAccessor getFieldAccessorOrNull(Class<?> clazz, String fieldName, Class<?> fieldType) {
|
||||
Field field = ExactReflection.fromClass(clazz, true).findField(fieldName);
|
||||
if ((field != null) && ((fieldType == null) || fieldType.isAssignableFrom(field.getType()))) {
|
||||
return Accessors.getFieldAccessor(field);
|
||||
}
|
||||
|
||||
// no matching field found
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field accessor from a given field that uses unchecked exceptions.
|
||||
*
|
||||
* @param field - the field.
|
||||
* @return The field accessor.
|
||||
*/
|
||||
public static FieldAccessor getFieldAccessor(Field field) {
|
||||
return MethodHandleHelper.getFieldAccessor(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field accessor that will cache the content of the field.
|
||||
* <p>
|
||||
* Note that we don't check if the underlying field has changed after the value has been cached, so it's best to use
|
||||
* this on final fields.
|
||||
*
|
||||
* @param inner - the accessor.
|
||||
* @return A cached field accessor.
|
||||
*/
|
||||
public static FieldAccessor getMemorizing(FieldAccessor inner) {
|
||||
return new MemorizingFieldAccessor(inner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a method accessor for a method with the given name and signature.
|
||||
*
|
||||
* @param instanceClass - the parent class.
|
||||
* @param methodName - the method name.
|
||||
* @param parameters - the parameters.
|
||||
* @return The method accessor.
|
||||
*/
|
||||
public static MethodAccessor getMethodAccessor(Class<?> instanceClass, String methodName, Class<?>... parameters) {
|
||||
Method method = ExactReflection.fromClass(instanceClass, true).getMethod(methodName, parameters);
|
||||
return Accessors.getMethodAccessor(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a method accessor for a field with the given name and equivalent type, or NULL.
|
||||
*
|
||||
* @param clazz - the declaration class.
|
||||
* @param methodName - the method name.
|
||||
* @return The method accessor, or NULL if not found.
|
||||
*/
|
||||
public static MethodAccessor getMethodAccessorOrNull(Class<?> clazz, String methodName, Class<?>... parameters) {
|
||||
Method method = ExactReflection.fromClass(clazz, true).findMethod(methodName, parameters);
|
||||
return method == null ? null : Accessors.getMethodAccessor(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a method accessor for a particular method, avoding checked exceptions.
|
||||
*
|
||||
* @param method - the method to access.
|
||||
* @return The method accessor.
|
||||
*/
|
||||
public static MethodAccessor getMethodAccessor(Method method) {
|
||||
return MethodHandleHelper.getMethodAccessor(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a constructor accessor for a constructor with the given signature.
|
||||
*
|
||||
* @param instanceClass - the parent class.
|
||||
* @param parameters - the parameters.
|
||||
* @return The constructor accessor.
|
||||
* @throws IllegalArgumentException If we cannot find this constructor.
|
||||
*/
|
||||
public static ConstructorAccessor getConstructorAccessor(Class<?> instanceClass, Class<?>... parameters) {
|
||||
Constructor<?> constructor = ExactReflection.fromClass(instanceClass, true).findConstructor(parameters);
|
||||
return Accessors.getConstructorAccessor(constructor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a specific constructor in a class.
|
||||
*
|
||||
* @param clazz - the class.
|
||||
* @param parameters - the signature of the constructor to find.
|
||||
* @return The constructor, or NULL if not found.
|
||||
*/
|
||||
public static ConstructorAccessor getConstructorAccessorOrNull(Class<?> clazz, Class<?>... parameters) {
|
||||
Constructor<?> constructor = ExactReflection.fromClass(clazz, true).findConstructor(parameters);
|
||||
return constructor == null ? null : Accessors.getConstructorAccessor(constructor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a constructor accessor for a particular constructor, avoding checked exceptions.
|
||||
*
|
||||
* @param constructor - the constructor to access.
|
||||
* @return The method accessor.
|
||||
*/
|
||||
public static ConstructorAccessor getConstructorAccessor(final Constructor<?> constructor) {
|
||||
return MethodHandleHelper.getConstructorAccessor(constructor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.accessors;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
public interface ConstructorAccessor {
|
||||
|
||||
/**
|
||||
* Invoke the underlying constructor.
|
||||
*
|
||||
* @param args - the arguments to pass to the method.
|
||||
* @return The return value, or NULL for void methods.
|
||||
*/
|
||||
Object invoke(Object... args);
|
||||
|
||||
/**
|
||||
* Retrieve the underlying constructor.
|
||||
*
|
||||
* @return The method.
|
||||
*/
|
||||
Constructor<?> getConstructor();
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.accessors;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
final class DefaultConstrutorAccessor implements ConstructorAccessor {
|
||||
|
||||
private final Constructor<?> constructor;
|
||||
private final MethodHandle constructorAccessor;
|
||||
|
||||
public DefaultConstrutorAccessor(Constructor<?> constructor, MethodHandle constructorAccessor) {
|
||||
this.constructor = constructor;
|
||||
this.constructorAccessor = constructorAccessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object... args) {
|
||||
try {
|
||||
return this.constructorAccessor.invokeExact(args);
|
||||
} catch (Throwable throwable) {
|
||||
throw new IllegalStateException("Unable to construct new instance using " + this.constructor, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Constructor<?> getConstructor() {
|
||||
return this.constructor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.accessors;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
final class DefaultFieldAccessor implements FieldAccessor {
|
||||
|
||||
private final Field field;
|
||||
private final boolean staticField;
|
||||
|
||||
private final MethodHandle setter;
|
||||
private final MethodHandle getter;
|
||||
|
||||
public DefaultFieldAccessor(Field field, MethodHandle setter, MethodHandle getter, boolean staticField) {
|
||||
this.field = Preconditions.checkNotNull(field, "field");
|
||||
this.setter = Preconditions.checkNotNull(setter, "setter");
|
||||
this.getter = Preconditions.checkNotNull(getter, "getter");
|
||||
this.staticField = staticField;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object instance) {
|
||||
try {
|
||||
// we need this check to as the handle will treat "null" as an instance too
|
||||
return this.staticField ? this.getter.invokeExact() : this.getter.invokeExact(instance);
|
||||
} catch (Throwable throwable) {
|
||||
throw new IllegalStateException("Unable to read field value of " + this.field, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object instance, Object value) {
|
||||
try {
|
||||
// we need this check to as the handle will treat "null" as an instance too
|
||||
if (this.staticField) {
|
||||
this.setter.invokeExact(value);
|
||||
} else {
|
||||
this.setter.invokeExact(instance, value);
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
throw new IllegalStateException("Unable to set value of field " + this.field, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Field getField() {
|
||||
return this.field;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.accessors;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
final class DefaultMethodAccessor implements MethodAccessor {
|
||||
|
||||
private final Method method;
|
||||
private final MethodHandle methodHandle;
|
||||
|
||||
public DefaultMethodAccessor(Method method, MethodHandle methodHandle, boolean staticMethod) {
|
||||
this.method = method;
|
||||
this.methodHandle = methodHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object target, Object... args) {
|
||||
try {
|
||||
return this.methodHandle.invoke(target, args);
|
||||
} catch (Throwable throwable) {
|
||||
throw new IllegalStateException("Unable to invoke method " + this.method, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Method getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.accessors;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* Represents an interface for accessing a field.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public interface FieldAccessor {
|
||||
|
||||
/**
|
||||
* Retrieve the value of a field for a particular instance.
|
||||
*
|
||||
* @param instance - the instance, or NULL for a static field.
|
||||
* @return The value of the field.
|
||||
* @throws IllegalStateException If the current security context prohibits reflection.
|
||||
*/
|
||||
Object get(Object instance);
|
||||
|
||||
/**
|
||||
* Set the value of a field for a particular instance.
|
||||
*
|
||||
* @param instance - the instance, or NULL for a static field.
|
||||
* @param value - the new value of the field.
|
||||
*/
|
||||
void set(Object instance, Object value);
|
||||
|
||||
/**
|
||||
* Retrieve the underlying field.
|
||||
*
|
||||
* @return The field.
|
||||
*/
|
||||
Field getField();
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.accessors;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
final class MemorizingFieldAccessor implements FieldAccessor {
|
||||
|
||||
// a marker object which indicates the value of the field wasn't yet read
|
||||
private static final Object NIL = new Object();
|
||||
|
||||
private final FieldAccessor inner;
|
||||
private volatile Object fieldValue = NIL;
|
||||
|
||||
public MemorizingFieldAccessor(FieldAccessor inner) {
|
||||
this.inner = inner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object instance) {
|
||||
if (this.fieldValue == NIL) {
|
||||
this.fieldValue = this.inner.get(instance);
|
||||
}
|
||||
|
||||
return this.fieldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object instance, Object value) {
|
||||
this.inner.set(instance, value);
|
||||
this.fieldValue = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Field getField() {
|
||||
return this.inner.getField();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.accessors;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Represents an interface for invoking a method.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public interface MethodAccessor {
|
||||
|
||||
/**
|
||||
* Invoke the underlying method.
|
||||
*
|
||||
* @param target - the target instance, or NULL for a static method.
|
||||
* @param args - the arguments to pass to the method.
|
||||
* @return The return value, or NULL for void methods.
|
||||
*/
|
||||
Object invoke(Object target, Object... args);
|
||||
|
||||
/**
|
||||
* Retrieve the underlying method.
|
||||
*
|
||||
* @return The method.
|
||||
*/
|
||||
Method getMethod();
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.accessors;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
final class MethodHandleHelper {
|
||||
|
||||
private static final Lookup LOOKUP;
|
||||
|
||||
// static fields, converted as "public Object get()" and "public void set(Object value)"
|
||||
private static final MethodType STATIC_FIELD_GETTER = MethodType.methodType(Object.class);
|
||||
private static final MethodType STATIC_FIELD_SETTER = MethodType.methodType(void.class, Object.class);
|
||||
// instance fields, converted as "public Object get(Object instance)" and "public void set(Object instance, Object value)"
|
||||
private static final MethodType VIRTUAL_FIELD_GETTER = MethodType.methodType(Object.class, Object.class);
|
||||
private static final MethodType VIRTUAL_FIELD_SETTER = MethodType.methodType(void.class, Object.class, Object.class);
|
||||
|
||||
static {
|
||||
Lookup lookup;
|
||||
try {
|
||||
// get the unsafe class
|
||||
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
|
||||
// get the unsafe instance
|
||||
Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe");
|
||||
theUnsafe.setAccessible(true);
|
||||
sun.misc.Unsafe unsafe = (sun.misc.Unsafe) theUnsafe.get(null);
|
||||
// get the trusted lookup field
|
||||
Field trustedLookup = Lookup.class.getDeclaredField("IMPL_LOOKUP");
|
||||
// get access to the base and offset value of it
|
||||
long offset = unsafe.staticFieldOffset(trustedLookup);
|
||||
Object baseValue = unsafe.staticFieldBase(trustedLookup);
|
||||
// get the trusted lookup instance
|
||||
lookup = (Lookup) unsafe.getObject(baseValue, offset);
|
||||
} catch (Exception exception) {
|
||||
//PluginLogger.log(Level.SEVERE, "Unable to retrieve trusted lookup", exception);
|
||||
lookup = MethodHandles.lookup();
|
||||
}
|
||||
|
||||
LOOKUP = lookup;
|
||||
}
|
||||
|
||||
// sealed class
|
||||
private MethodHandleHelper() {
|
||||
}
|
||||
|
||||
public static MethodAccessor getMethodAccessor(Method method) {
|
||||
Preconditions.checkNotNull(method, "method");
|
||||
|
||||
try {
|
||||
MethodHandle unreflected = LOOKUP.unreflect(method);
|
||||
boolean staticMethod = Modifier.isStatic(method.getModifiers());
|
||||
|
||||
MethodHandle generified = convertToGeneric(unreflected, staticMethod, false);
|
||||
return new DefaultMethodAccessor(method, generified, staticMethod);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Unable to access method " + method, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static ConstructorAccessor getConstructorAccessor(Constructor<?> constructor) {
|
||||
Preconditions.checkNotNull(constructor, "constructor");
|
||||
|
||||
try {
|
||||
MethodHandle unreflected = LOOKUP.unreflectConstructor(constructor);
|
||||
MethodHandle generified = convertToGeneric(unreflected, false, true);
|
||||
|
||||
return new DefaultConstrutorAccessor(constructor, generified);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new IllegalStateException("Unable to access constructor " + constructor, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static FieldAccessor getFieldAccessor(Field field) {
|
||||
Preconditions.checkNotNull(field, "field");
|
||||
|
||||
try {
|
||||
boolean staticField = Modifier.isStatic(field.getModifiers());
|
||||
|
||||
// java hates us - unreflecting a trusted field always results in an exception, finding them doesn't...
|
||||
MethodHandle getter;
|
||||
MethodHandle setter;
|
||||
if (staticField) {
|
||||
getter = LOOKUP.findStaticGetter(field.getDeclaringClass(), field.getName(), field.getType());
|
||||
setter = LOOKUP.findStaticSetter(field.getDeclaringClass(), field.getName(), field.getType());
|
||||
} else {
|
||||
getter = LOOKUP.findGetter(field.getDeclaringClass(), field.getName(), field.getType());
|
||||
setter = LOOKUP.findSetter(field.getDeclaringClass(), field.getName(), field.getType());
|
||||
}
|
||||
|
||||
// generify the method type so that we don't need to worry about it when using the handles
|
||||
if (staticField) {
|
||||
getter = getter.asType(STATIC_FIELD_GETTER);
|
||||
setter = setter.asType(STATIC_FIELD_SETTER);
|
||||
} else {
|
||||
getter = getter.asType(VIRTUAL_FIELD_GETTER);
|
||||
setter = setter.asType(VIRTUAL_FIELD_SETTER);
|
||||
}
|
||||
|
||||
if (getter == null) {
|
||||
throw new IllegalStateException("Unable to access field " + field + ". Could not find getter");
|
||||
}
|
||||
|
||||
if (setter == null) {
|
||||
throw new IllegalStateException("Unable to access field " + field + ". Could not find setter");
|
||||
}
|
||||
|
||||
return new DefaultFieldAccessor(field, setter, getter, staticField);
|
||||
} catch (IllegalAccessException | NoSuchFieldException ex) {
|
||||
// NoSuchFieldException can never happen, the field always exists
|
||||
throw new IllegalStateException("Unable to access field " + field, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodHandle convertToGeneric(MethodHandle handle, boolean staticMethod, boolean ctor) {
|
||||
MethodHandle target = handle.asFixedArity();
|
||||
// special thing - we do not need the trailing array if we have 0 arguments anyway
|
||||
int paramCount = handle.type().parameterCount() - (ctor || staticMethod ? 0 : 1);
|
||||
MethodType methodType = MethodType.genericMethodType(ctor ? 0 : 1, true);
|
||||
// spread the arguments we give into the handle
|
||||
target = target.asSpreader(Object[].class, paramCount);
|
||||
// adds a leading 'this' argument which we can ignore
|
||||
if (staticMethod) {
|
||||
target = MethodHandles.dropArguments(target, 0, Object.class);
|
||||
}
|
||||
// convert the type to finish
|
||||
return target.asType(methodType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.fuzzy;
|
||||
|
||||
/**
|
||||
* Represents a matcher for fields, methods, constructors and classes.
|
||||
* <p>
|
||||
* This class should ideally never expose mutable state. Its round number must be immutable.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface AbstractFuzzyMatcher<T> {
|
||||
|
||||
/**
|
||||
* Determine if the given value is a match.
|
||||
*
|
||||
* @param value - the value to match.
|
||||
* @param parent - the parent container, or NULL if this value is the root.
|
||||
* @return TRUE if it is a match, FALSE otherwise.
|
||||
*/
|
||||
boolean isMatch(T value, Object parent);
|
||||
|
||||
/**
|
||||
* Create a fuzzy matcher that returns the opposite result of the current matcher.
|
||||
*
|
||||
* @return An inverted fuzzy matcher.
|
||||
*/
|
||||
default AbstractFuzzyMatcher<T> inverted() {
|
||||
return (value, parent) -> !this.isMatch(value, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that this and the given matcher be TRUE.
|
||||
*
|
||||
* @param other - the other fuzzy matcher.
|
||||
* @return A combined fuzzy matcher.
|
||||
*/
|
||||
default AbstractFuzzyMatcher<T> and(final AbstractFuzzyMatcher<T> other) {
|
||||
// They both have to be true
|
||||
return (value, parent) -> this.isMatch(value, parent) && other.isMatch(value, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that either this or the other given matcher be TRUE.
|
||||
*
|
||||
* @param other - the other fuzzy matcher.
|
||||
* @return A combined fuzzy matcher.
|
||||
*/
|
||||
default AbstractFuzzyMatcher<T> or(final AbstractFuzzyMatcher<T> other) {
|
||||
// Either can be true
|
||||
return (value, parent) -> this.isMatch(value, parent) || other.isMatch(value, parent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.fuzzy;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* Represents a matcher that matches members.
|
||||
*
|
||||
* @param <T> - type that it matches.
|
||||
* @author Kristian
|
||||
*/
|
||||
public abstract class AbstractFuzzyMember<T extends Member> implements AbstractFuzzyMatcher<T> {
|
||||
|
||||
// Accessibility matchers
|
||||
protected int modifiersRequired;
|
||||
protected int modifiersBanned;
|
||||
|
||||
protected Pattern nameRegex;
|
||||
protected AbstractFuzzyMatcher<Class<?>> declaringMatcher = ClassTypeMatcher.MATCH_ALL;
|
||||
|
||||
/**
|
||||
* Whether this contract can be modified.
|
||||
*/
|
||||
protected transient boolean sealed;
|
||||
|
||||
protected AbstractFuzzyMember() {
|
||||
// Only allow construction through the builder
|
||||
}
|
||||
|
||||
// Clone a given contract
|
||||
protected AbstractFuzzyMember(AbstractFuzzyMember<T> other) {
|
||||
this.modifiersRequired = other.modifiersRequired;
|
||||
this.modifiersBanned = other.modifiersBanned;
|
||||
this.nameRegex = other.nameRegex;
|
||||
this.declaringMatcher = other.declaringMatcher;
|
||||
this.sealed = true;
|
||||
}
|
||||
|
||||
private static String getBitView(int value, int bits) {
|
||||
if ((bits < 0) || (bits > 31)) {
|
||||
throw new IllegalArgumentException("Bits must be a value between 0 and 32");
|
||||
}
|
||||
|
||||
// Extract our needed bits
|
||||
int snipped = value & ((1 << bits) - 1);
|
||||
return Integer.toBinaryString(snipped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before a builder is building a member and copying its state.
|
||||
* <p>
|
||||
* Use this to prepare any special values.
|
||||
*/
|
||||
protected void prepareBuild() {
|
||||
// No need to prepare anything
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a bit field of every {@link java.lang.reflect.Modifier Modifier} that is required for the member to
|
||||
* match.
|
||||
*
|
||||
* @return A required modifier bit field.
|
||||
*/
|
||||
public int getModifiersRequired() {
|
||||
return this.modifiersRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a bit field of every {@link java.lang.reflect.Modifier Modifier} that must not be present for the member
|
||||
* to match.
|
||||
*
|
||||
* @return A banned modifier bit field.
|
||||
*/
|
||||
public int getModifiersBanned() {
|
||||
return this.modifiersBanned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the regular expression pattern that is used to match the name of a member.
|
||||
*
|
||||
* @return The regex matching a name, or NULL if everything matches.
|
||||
*/
|
||||
public Pattern getNameRegex() {
|
||||
return this.nameRegex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a class matcher for the declaring class of the member.
|
||||
*
|
||||
* @return An object matching the declaring class.
|
||||
*/
|
||||
public AbstractFuzzyMatcher<Class<?>> getDeclaringMatcher() {
|
||||
return this.declaringMatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(T value, Object parent) {
|
||||
int mods = value.getModifiers();
|
||||
|
||||
// Match accessibility and name
|
||||
return ((mods & this.modifiersRequired) == this.modifiersRequired)
|
||||
&& ((mods & this.modifiersBanned) == 0)
|
||||
&& this.declaringMatcher.isMatch(value.getDeclaringClass(), value)
|
||||
&& this.isNameMatch(value.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given name matches the current member matcher.
|
||||
*
|
||||
* @param name - the name to match.
|
||||
* @return TRUE if the name matches, FALSE otherwise.
|
||||
*/
|
||||
private boolean isNameMatch(String name) {
|
||||
if (this.nameRegex == null) {
|
||||
return true;
|
||||
} else {
|
||||
return this.nameRegex.matcher(name).matches();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getKeyValueView().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a view of this matcher as a key-value map.
|
||||
* <p>
|
||||
* Used by {@link #toString()} to print a representation of this object.
|
||||
*
|
||||
* @return A modifiable key-value view.
|
||||
*/
|
||||
protected Map<String, Object> getKeyValueView() {
|
||||
Map<String, Object> map = Maps.newLinkedHashMap();
|
||||
|
||||
// Build our representation
|
||||
if ((this.modifiersRequired != Integer.MAX_VALUE) || (this.modifiersBanned != 0)) {
|
||||
map.put("modifiers", String.format(
|
||||
"[required: %s, banned: %s]",
|
||||
getBitView(this.modifiersRequired, 16),
|
||||
getBitView(this.modifiersBanned, 16)));
|
||||
}
|
||||
|
||||
if (this.nameRegex != null) {
|
||||
map.put("name", this.nameRegex.pattern());
|
||||
}
|
||||
|
||||
if (this.declaringMatcher != ClassTypeMatcher.MATCH_ALL) {
|
||||
map.put("declaring", this.declaringMatcher);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
} else if (obj instanceof AbstractFuzzyMember) {
|
||||
AbstractFuzzyMember<?> other = (AbstractFuzzyMember<?>) obj;
|
||||
return (this.modifiersBanned == other.modifiersBanned)
|
||||
&& (this.modifiersRequired == other.modifiersRequired)
|
||||
&& FuzzyMatchers.checkPattern(this.nameRegex, other.nameRegex)
|
||||
&& Objects.equals(this.declaringMatcher, other.declaringMatcher);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(
|
||||
this.modifiersBanned,
|
||||
this.modifiersRequired,
|
||||
this.nameRegex != null ? this.nameRegex.pattern() : null,
|
||||
this.declaringMatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a builder of a fuzzy member contract.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public static abstract class Builder<T extends AbstractFuzzyMember<?>> {
|
||||
|
||||
protected T member = this.initialMember();
|
||||
|
||||
/**
|
||||
* Add a given bit-field of required modifiers for every matching member.
|
||||
*
|
||||
* @param modifier - bit-field of modifiers that are required.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder<T> requireModifier(int modifier) {
|
||||
this.member.modifiersRequired |= modifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that every matching member is public.
|
||||
*
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder<T> requirePublic() {
|
||||
return this.requireModifier(Modifier.PUBLIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a given bit-field of modifers that will skip or ignore members.
|
||||
*
|
||||
* @param modifier - bit-field of modifiers to skip or ignore.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder<T> banModifier(int modifier) {
|
||||
this.member.modifiersBanned |= modifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the regular expresson that matches a members name.
|
||||
*
|
||||
* @param regex - new regular expression of valid names.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder<T> nameRegex(String regex) {
|
||||
this.member.nameRegex = Pattern.compile(regex);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the regular expression pattern that matches a members name.
|
||||
*
|
||||
* @param pattern - regular expression pattern for a valid name.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder<T> nameRegex(Pattern pattern) {
|
||||
this.member.nameRegex = pattern;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the exact name of the member we are matching.
|
||||
* <p>
|
||||
* This will overwrite the regular expression rule.
|
||||
*
|
||||
* @param name - exact name.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder<T> nameExact(String name) {
|
||||
return this.nameRegex(Pattern.quote(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that a member is defined by this exact class.
|
||||
*
|
||||
* @param declaringClass - the declaring class of any matching member.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder<T> declaringClassExactType(Class<?> declaringClass) {
|
||||
this.member.declaringMatcher = FuzzyMatchers.matchExact(declaringClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that a member is defined by this exact class, or any super class.
|
||||
*
|
||||
* @param declaringClass - the declaring class.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder<T> declaringClassSuperOf(Class<?> declaringClass) {
|
||||
this.member.declaringMatcher = FuzzyMatchers.matchSuper(declaringClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that a member is defined by this exact class, or any super class.
|
||||
*
|
||||
* @param declaringClass - the declaring class.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder<T> declaringClassDerivedOf(Class<?> declaringClass) {
|
||||
this.member.declaringMatcher = FuzzyMatchers.matchDerived(declaringClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that a member is defined by a class that matches the given matcher.
|
||||
*
|
||||
* @param classMatcher - class matcher.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder<T> declaringClassMatching(AbstractFuzzyMatcher<Class<?>> classMatcher) {
|
||||
this.member.declaringMatcher = classMatcher;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new instance of the current type.
|
||||
*
|
||||
* @return New instance.
|
||||
*/
|
||||
@Nonnull
|
||||
protected abstract T initialMember();
|
||||
|
||||
/**
|
||||
* Build a new instance of this type.
|
||||
* <p>
|
||||
* Builders should call {@link AbstractFuzzyMember#prepareBuild()} when constructing new objects.
|
||||
*
|
||||
* @return New instance of this type.
|
||||
*/
|
||||
public abstract T build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.fuzzy;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Determine if a class matches based on its name using a regular expression.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
final class ClassRegexMatcher implements AbstractFuzzyMatcher<Class<?>> {
|
||||
|
||||
private final Pattern regex;
|
||||
|
||||
public ClassRegexMatcher(Pattern regex) {
|
||||
this.regex = regex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(Class<?> value, Object parent) {
|
||||
if ((value != null) && (this.regex != null)) {
|
||||
return this.regex.matcher(value.getCanonicalName()).matches();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{ type matches \"" + this.regex.pattern() + "\" }";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.fuzzy;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents a class matcher that checks for equality using a given set of classes.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
final class ClassSetMatcher implements AbstractFuzzyMatcher<Class<?>> {
|
||||
|
||||
private final Set<Class<?>> classes;
|
||||
|
||||
public ClassSetMatcher(Set<Class<?>> classes) {
|
||||
this.classes = classes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(Class<?> value, Object parent) {
|
||||
return this.classes.contains(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{ type any of " + this.classes + " }";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.fuzzy;
|
||||
|
||||
/**
|
||||
* Used to check class equality.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
final class ClassTypeMatcher implements AbstractFuzzyMatcher<Class<?>> {
|
||||
|
||||
/**
|
||||
* Match any class.
|
||||
*/
|
||||
public static final ClassTypeMatcher MATCH_ALL = new ClassTypeMatcher(null, MatchVariant.MATCH_SUPER);
|
||||
|
||||
private final Class<?> matcher;
|
||||
private final MatchVariant variant;
|
||||
|
||||
/**
|
||||
* Constructs a new class matcher.
|
||||
*
|
||||
* @param matcher - the matching class, or NULL to represent anything.
|
||||
* @param variant - options specifying the matching rules.
|
||||
*/
|
||||
ClassTypeMatcher(Class<?> matcher, MatchVariant variant) {
|
||||
this.matcher = matcher;
|
||||
this.variant = variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given class is equivalent.
|
||||
* <p>
|
||||
* If the matcher is NULL, the result will only be TRUE if we're not matching exactly.
|
||||
*
|
||||
* @param input - the input class defined in the source file.
|
||||
* @param parent - the container that holds a reference to this class.
|
||||
* @return TRUE if input matches according to the rules in {@link #getMatchVariant()}, FALSE otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean isMatch(Class<?> input, Object parent) {
|
||||
if (input == null) {
|
||||
throw new IllegalArgumentException("Input class cannot be NULL.");
|
||||
}
|
||||
|
||||
// if no type to check against is given just ensure that we're not strict checking
|
||||
if (this.matcher == null) {
|
||||
return this.variant != MatchVariant.MATCH_EXACT;
|
||||
}
|
||||
|
||||
switch (this.variant) {
|
||||
case MATCH_EXACT:
|
||||
return this.matcher.equals(input);
|
||||
case MATCH_DERIVED:
|
||||
return this.matcher.isAssignableFrom(input);
|
||||
case MATCH_SUPER:
|
||||
return input.isAssignableFrom(this.matcher);
|
||||
default:
|
||||
// unknown option?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the class we're comparing against.
|
||||
*
|
||||
* @return Class to compare against.
|
||||
*/
|
||||
public Class<?> getMatcher() {
|
||||
return this.matcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* The matching rules for this class matcher.
|
||||
*
|
||||
* @return The current matching option.
|
||||
*/
|
||||
public MatchVariant getMatchVariant() {
|
||||
return this.variant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this.variant) {
|
||||
case MATCH_EXACT:
|
||||
return "{ type exactly " + this.matcher + " }";
|
||||
case MATCH_SUPER:
|
||||
return "{ type " + this.matcher + " instanceof input }";
|
||||
case MATCH_DERIVED:
|
||||
return "{ type input instanceof " + this.matcher + " }";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown match variant " + this.variant);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Different matching rules.
|
||||
*/
|
||||
enum MatchVariant {
|
||||
|
||||
/**
|
||||
* Match classes exactly.
|
||||
*/
|
||||
MATCH_EXACT,
|
||||
|
||||
/**
|
||||
* A match if the input class is a superclass of the matcher class, or the same class.
|
||||
*/
|
||||
MATCH_SUPER,
|
||||
|
||||
/**
|
||||
* A match if the input class is a derived class of the matcher class, or the same class.
|
||||
*/
|
||||
MATCH_DERIVED
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.fuzzy;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.github.joelgodofwar.mmh.common.reflect.FuzzyReflection;
|
||||
import com.github.joelgodofwar.mmh.common.reflect.MethodInfo;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Determine if a given class implements a given fuzzy (duck typed) contract.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class FuzzyClassContract implements AbstractFuzzyMatcher<Class<?>> {
|
||||
|
||||
private final ImmutableList<AbstractFuzzyMatcher<Field>> fieldContracts;
|
||||
private final ImmutableList<AbstractFuzzyMatcher<MethodInfo>> methodContracts;
|
||||
private final ImmutableList<AbstractFuzzyMatcher<MethodInfo>> constructorContracts;
|
||||
|
||||
private final ImmutableList<AbstractFuzzyMatcher<Class<?>>> baseclassContracts;
|
||||
private final ImmutableList<AbstractFuzzyMatcher<Class<?>>> interfaceContracts;
|
||||
|
||||
/**
|
||||
* Constructs a new fuzzy class contract with the given contracts.
|
||||
*
|
||||
* @param builder - the builder that is constructing us.
|
||||
*/
|
||||
private FuzzyClassContract(Builder builder) {
|
||||
this.fieldContracts = ImmutableList.copyOf(builder.fieldContracts);
|
||||
this.methodContracts = ImmutableList.copyOf(builder.methodContracts);
|
||||
this.constructorContracts = ImmutableList.copyOf(builder.constructorContracts);
|
||||
this.baseclassContracts = ImmutableList.copyOf(builder.baseclassContracts);
|
||||
this.interfaceContracts = ImmutableList.copyOf(builder.interfaceContracts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new fuzzy class contract builder.
|
||||
*
|
||||
* @return A new builder.
|
||||
*/
|
||||
public static Builder newBuilder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an immutable list of every field contract.
|
||||
* <p>
|
||||
* This list is ordered in descending order of priority.
|
||||
*
|
||||
* @return List of every field contract.
|
||||
*/
|
||||
public ImmutableList<AbstractFuzzyMatcher<Field>> getFieldContracts() {
|
||||
return this.fieldContracts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an immutable list of every method contract.
|
||||
* <p>
|
||||
* This list is ordered in descending order of priority.
|
||||
*
|
||||
* @return List of every method contract.
|
||||
*/
|
||||
public ImmutableList<AbstractFuzzyMatcher<MethodInfo>> getMethodContracts() {
|
||||
return this.methodContracts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an immutable list of every constructor contract.
|
||||
* <p>
|
||||
* This list is ordered in descending order of priority.
|
||||
*
|
||||
* @return List of every constructor contract.
|
||||
*/
|
||||
public ImmutableList<AbstractFuzzyMatcher<MethodInfo>> getConstructorContracts() {
|
||||
return this.constructorContracts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an immutable list of every baseclass contract.
|
||||
* <p>
|
||||
* This list is ordered in descending order of priority.
|
||||
*
|
||||
* @return List of every baseclass contract.
|
||||
*/
|
||||
public ImmutableList<AbstractFuzzyMatcher<Class<?>>> getBaseclassContracts() {
|
||||
return this.baseclassContracts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an immutable list of every interface contract.
|
||||
* <p>
|
||||
* This list is ordered in descending order of priority.
|
||||
*
|
||||
* @return List of every interface contract.
|
||||
*/
|
||||
public ImmutableList<AbstractFuzzyMatcher<Class<?>>> getInterfaceContracts() {
|
||||
return this.interfaceContracts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(Class<?> value, Object parent) {
|
||||
FuzzyReflection reflection = FuzzyReflection.fromClass(value, true);
|
||||
|
||||
// Make sure all the contracts are valid
|
||||
return this.processValue(value.getSuperclass(), parent, this.baseclassContracts)
|
||||
&& this.processContracts(Arrays.asList(value.getInterfaces()), parent, this.interfaceContracts)
|
||||
&& this.processContracts(reflection.getFields(), value, this.fieldContracts)
|
||||
&& this.processContracts(MethodInfo.fromMethods(reflection.getMethods()), value, this.methodContracts)
|
||||
&& this.processContracts(MethodInfo.fromConstructors(value.getDeclaredConstructors()), value,
|
||||
this.constructorContracts);
|
||||
}
|
||||
|
||||
private <T> boolean processContracts(Collection<T> values, Object parent, List<AbstractFuzzyMatcher<T>> matchers) {
|
||||
// they all match if no values are present
|
||||
if (values.isEmpty() || matchers.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if all contracts match the given objects
|
||||
int acceptingMatchers = 0;
|
||||
for (T value : values) {
|
||||
if (this.processValue(value, parent, matchers)) {
|
||||
acceptingMatchers++;
|
||||
// if all matchers found one match we're done
|
||||
if (acceptingMatchers == matchers.size()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private <T> boolean processValue(T value, Object parent, List<AbstractFuzzyMatcher<T>> matchers) {
|
||||
// check if all given contracts match the given value
|
||||
for (AbstractFuzzyMatcher<T> matcher : matchers) {
|
||||
if (!matcher.isMatch(value, parent)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// they all match
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder("FuzzyClassContract={\n");
|
||||
|
||||
// append all subcontracts
|
||||
if (!this.fieldContracts.isEmpty()) {
|
||||
builder.append(" fields=").append(this.fieldContracts).append("\n");
|
||||
}
|
||||
|
||||
if (!this.methodContracts.isEmpty()) {
|
||||
builder.append(" methods=").append(this.methodContracts).append("\n");
|
||||
}
|
||||
|
||||
if (!this.constructorContracts.isEmpty()) {
|
||||
builder.append(" constructors=").append(this.constructorContracts).append("\n");
|
||||
}
|
||||
|
||||
if (!this.baseclassContracts.isEmpty()) {
|
||||
builder.append(" baseClasses=").append(this.baseclassContracts).append("\n");
|
||||
}
|
||||
|
||||
if (!this.interfaceContracts.isEmpty()) {
|
||||
builder.append(" interfaceClasses=").append(this.interfaceContracts).append("\n");
|
||||
}
|
||||
|
||||
// finish off
|
||||
return builder.append("}").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a class contract builder.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public static final class Builder {
|
||||
|
||||
private final List<AbstractFuzzyMatcher<Field>> fieldContracts = new ArrayList<>();
|
||||
private final List<AbstractFuzzyMatcher<MethodInfo>> methodContracts = new ArrayList<>();
|
||||
private final List<AbstractFuzzyMatcher<MethodInfo>> constructorContracts = new ArrayList<>();
|
||||
|
||||
private final List<AbstractFuzzyMatcher<Class<?>>> baseclassContracts = new ArrayList<>();
|
||||
private final List<AbstractFuzzyMatcher<Class<?>>> interfaceContracts = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Add a new field contract.
|
||||
*
|
||||
* @param matcher - new field contract.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder field(AbstractFuzzyMatcher<Field> matcher) {
|
||||
this.fieldContracts.add(matcher);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new field contract via a builder.
|
||||
*
|
||||
* @param builder - builder for the new field contract.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder field(FuzzyFieldContract.Builder builder) {
|
||||
return this.field(builder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new method contract.
|
||||
*
|
||||
* @param matcher - new method contract.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder method(AbstractFuzzyMatcher<MethodInfo> matcher) {
|
||||
this.methodContracts.add(matcher);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new method contract via a builder.
|
||||
*
|
||||
* @param builder - builder for the new method contract.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder method(FuzzyMethodContract.Builder builder) {
|
||||
return this.method(builder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new constructor contract.
|
||||
*
|
||||
* @param matcher - new constructor contract.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder constructor(AbstractFuzzyMatcher<MethodInfo> matcher) {
|
||||
this.constructorContracts.add(matcher);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new constructor contract via a builder.
|
||||
*
|
||||
* @param builder - builder for the new constructor contract.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder constructor(FuzzyMethodContract.Builder builder) {
|
||||
return this.constructor(builder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new base class contract.
|
||||
*
|
||||
* @param matcher - new base class contract.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder baseclass(AbstractFuzzyMatcher<Class<?>> matcher) {
|
||||
this.baseclassContracts.add(matcher);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new base class contract.
|
||||
*
|
||||
* @param builder - builder for the new base class contract.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder baseclass(FuzzyClassContract.Builder builder) {
|
||||
return this.baseclass(builder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new interface contract.
|
||||
*
|
||||
* @param matcher - new interface contract.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder interfaces(AbstractFuzzyMatcher<Class<?>> matcher) {
|
||||
this.interfaceContracts.add(matcher);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new interface contract.
|
||||
*
|
||||
* @param builder - builder for the new interface contract.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder interfaces(FuzzyClassContract.Builder builder) {
|
||||
return this.interfaces(builder.build());
|
||||
}
|
||||
|
||||
public FuzzyClassContract build() {
|
||||
// Construct a new class matcher
|
||||
return new FuzzyClassContract(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.fuzzy;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Represents a field matcher.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class FuzzyFieldContract extends AbstractFuzzyMember<Field> {
|
||||
|
||||
private AbstractFuzzyMatcher<Class<?>> typeMatcher = ClassTypeMatcher.MATCH_ALL;
|
||||
|
||||
private FuzzyFieldContract() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new field contract from the given contract.
|
||||
*
|
||||
* @param other - the contract to clone.
|
||||
*/
|
||||
private FuzzyFieldContract(FuzzyFieldContract other) {
|
||||
super(other);
|
||||
this.typeMatcher = other.typeMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Match a field by its type.
|
||||
*
|
||||
* @param matcher - the type to match.
|
||||
* @return The field contract.
|
||||
*/
|
||||
public static FuzzyFieldContract matchType(AbstractFuzzyMatcher<Class<?>> matcher) {
|
||||
return newBuilder().typeMatches(matcher).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new fuzzy field contract builder.
|
||||
*
|
||||
* @return New fuzzy field contract builder.
|
||||
*/
|
||||
public static Builder newBuilder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the class matcher that matches the type of a field.
|
||||
*
|
||||
* @return The class matcher.
|
||||
*/
|
||||
public AbstractFuzzyMatcher<Class<?>> getTypeMatcher() {
|
||||
return this.typeMatcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(Field value, Object parent) {
|
||||
if (super.isMatch(value, parent)) {
|
||||
return this.typeMatcher.isMatch(value.getType(), value);
|
||||
}
|
||||
|
||||
// No match
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> getKeyValueView() {
|
||||
Map<String, Object> member = super.getKeyValueView();
|
||||
if (this.typeMatcher != ClassTypeMatcher.MATCH_ALL) {
|
||||
member.put("type", this.typeMatcher);
|
||||
}
|
||||
|
||||
return member;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a builder for a field matcher.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public static class Builder extends AbstractFuzzyMember.Builder<FuzzyFieldContract> {
|
||||
|
||||
@Override
|
||||
public Builder requireModifier(int modifier) {
|
||||
super.requireModifier(modifier);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder banModifier(int modifier) {
|
||||
super.banModifier(modifier);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder requirePublic() {
|
||||
super.requirePublic();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder nameRegex(String regex) {
|
||||
super.nameRegex(regex);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder nameRegex(Pattern pattern) {
|
||||
super.nameRegex(pattern);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder nameExact(String name) {
|
||||
super.nameExact(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public Builder declaringClassExactType(Class<?> declaringClass) {
|
||||
super.declaringClassExactType(declaringClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder declaringClassSuperOf(Class<?> declaringClass) {
|
||||
super.declaringClassSuperOf(declaringClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder declaringClassDerivedOf(Class<?> declaringClass) {
|
||||
super.declaringClassDerivedOf(declaringClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder declaringClassMatching(AbstractFuzzyMatcher<Class<?>> classMatcher) {
|
||||
super.declaringClassMatching(classMatcher);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
protected FuzzyFieldContract initialMember() {
|
||||
return new FuzzyFieldContract();
|
||||
}
|
||||
|
||||
public Builder typeExact(Class<?> type) {
|
||||
this.member.typeMatcher = FuzzyMatchers.matchExact(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder typeSuperOf(Class<?> type) {
|
||||
this.member.typeMatcher = FuzzyMatchers.matchSuper(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder typeDerivedOf(Class<?> type) {
|
||||
this.member.typeMatcher = FuzzyMatchers.matchDerived(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder typeMatches(AbstractFuzzyMatcher<Class<?>> matcher) {
|
||||
this.member.typeMatcher = matcher;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FuzzyFieldContract build() {
|
||||
this.member.prepareBuild();
|
||||
return new FuzzyFieldContract(this.member);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.fuzzy;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.github.joelgodofwar.mmh.common.reflect.fuzzy.ClassTypeMatcher.MatchVariant;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* Contains factory methods for matching classes.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class FuzzyMatchers {
|
||||
|
||||
// Constant matchers
|
||||
private static final AbstractFuzzyMatcher<Class<?>> MATCH_ALL = (value, parent) -> true;
|
||||
|
||||
private FuzzyMatchers() {
|
||||
// Don't make this constructable
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher that matches an array with a given component matcher.
|
||||
*
|
||||
* @param componentMatcher - the component matcher.
|
||||
* @return A new array matcher.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchArray(AbstractFuzzyMatcher<Class<?>> componentMatcher) {
|
||||
return (value, parent) -> value.isArray() && componentMatcher.isMatch(value.getComponentType(), parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a fuzzy matcher that will match any class.
|
||||
*
|
||||
* @return A class matcher.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchAll() {
|
||||
return MATCH_ALL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher that matches types exactly.
|
||||
*
|
||||
* @param matcher - the matching class.
|
||||
* @return A new class matcher.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchExact(Class<?> matcher) {
|
||||
return new ClassTypeMatcher(matcher, MatchVariant.MATCH_EXACT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher that matches any of the given classes exactly.
|
||||
*
|
||||
* @param classes - list of classes to match.
|
||||
* @return A new class matcher.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchAnyOf(Class<?>... classes) {
|
||||
return matchAnyOf(Sets.newHashSet(classes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher that matches any of the given classes exactly.
|
||||
*
|
||||
* @param classes - set of classes to match.
|
||||
* @return A new class matcher.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchAnyOf(Set<Class<?>> classes) {
|
||||
return new ClassSetMatcher(classes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher that matches super types of the given class.
|
||||
*
|
||||
* @param matcher - the matching type must be a super class of this type.
|
||||
* @return A new class matcher.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchSuper(Class<?> matcher) {
|
||||
return new ClassTypeMatcher(matcher, MatchVariant.MATCH_SUPER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher that matches derived types of the given class.
|
||||
*
|
||||
* @param matcher - the matching type must be a derived class of this type.
|
||||
* @return A new class matcher.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchDerived(Class<?> matcher) {
|
||||
return new ClassTypeMatcher(matcher, MatchVariant.MATCH_DERIVED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher based on the canonical names of classes.
|
||||
*
|
||||
* @param regex - regular expression pattern matching class names.
|
||||
* @return A fuzzy class matcher based on name.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchRegex(final Pattern regex) {
|
||||
return new ClassRegexMatcher(regex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a class matcher based on the canonical names of classes.
|
||||
*
|
||||
* @param regex - regular expression matching class names.
|
||||
* @return A fuzzy class matcher based on name.
|
||||
*/
|
||||
public static AbstractFuzzyMatcher<Class<?>> matchRegex(String regex) {
|
||||
return FuzzyMatchers.matchRegex(Pattern.compile(regex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if two patterns are the same.
|
||||
* <p>
|
||||
* Note that two patterns may be functionally the same, but nevertheless be different.
|
||||
*
|
||||
* @param a - the first pattern.
|
||||
* @param b - the second pattern.
|
||||
* @return TRUE if they are compiled from the same pattern, FALSE otherwise.
|
||||
*/
|
||||
static boolean checkPattern(Pattern a, Pattern b) {
|
||||
if (a == null) {
|
||||
return b == null;
|
||||
} else if (b == null) {
|
||||
return false;
|
||||
} else if (a == b) {
|
||||
return true;
|
||||
} else {
|
||||
return a.pattern().equals(b.pattern());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,564 @@
|
||||
package com.github.joelgodofwar.mmh.common.reflect.fuzzy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.github.joelgodofwar.mmh.common.reflect.MethodInfo;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Represents a contract for matching methods or constructors.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class FuzzyMethodContract extends AbstractFuzzyMember<MethodInfo> {
|
||||
|
||||
// Match return value
|
||||
private AbstractFuzzyMatcher<Class<?>> returnMatcher = ClassTypeMatcher.MATCH_ALL;
|
||||
// Handle parameters and exceptions
|
||||
private List<ParameterClassMatcher> paramMatchers;
|
||||
private List<ParameterClassMatcher> exceptionMatchers;
|
||||
// Expected parameter count
|
||||
private Integer paramCount;
|
||||
|
||||
private FuzzyMethodContract() {
|
||||
// Only allow construction from the builder
|
||||
this.paramMatchers = new ArrayList<>();
|
||||
this.exceptionMatchers = new ArrayList<>();
|
||||
}
|
||||
|
||||
private FuzzyMethodContract(FuzzyMethodContract other) {
|
||||
super(other);
|
||||
this.returnMatcher = other.returnMatcher;
|
||||
this.paramMatchers = other.paramMatchers;
|
||||
this.exceptionMatchers = other.exceptionMatchers;
|
||||
this.paramCount = other.paramCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a method contract builder.
|
||||
*
|
||||
* @return Method contract builder.
|
||||
*/
|
||||
public static Builder newBuilder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new immutable copy of the given method contract.
|
||||
*
|
||||
* @param other - the contract to clone.
|
||||
* @return A immutable copy of the given contract.
|
||||
*/
|
||||
private static FuzzyMethodContract immutableCopy(FuzzyMethodContract other) {
|
||||
FuzzyMethodContract copy = new FuzzyMethodContract(other);
|
||||
|
||||
// Ensure that the lists are immutable
|
||||
copy.paramMatchers = ImmutableList.copyOf(copy.paramMatchers);
|
||||
copy.exceptionMatchers = ImmutableList.copyOf(copy.exceptionMatchers);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the class matcher for the return type.
|
||||
*
|
||||
* @return Class matcher for the return type.
|
||||
*/
|
||||
public AbstractFuzzyMatcher<Class<?>> getReturnMatcher() {
|
||||
return this.returnMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an immutable list of every parameter matcher for this method.
|
||||
*
|
||||
* @return Immutable list of every parameter matcher.
|
||||
*/
|
||||
public ImmutableList<ParameterClassMatcher> getParamMatchers() {
|
||||
if (this.paramMatchers instanceof ImmutableList) {
|
||||
return (ImmutableList<ParameterClassMatcher>) this.paramMatchers;
|
||||
} else {
|
||||
throw new IllegalStateException("Lists haven't been sealed yet.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an immutable list of every exception matcher for this method.
|
||||
*
|
||||
* @return Immutable list of every exception matcher.
|
||||
*/
|
||||
public List<ParameterClassMatcher> getExceptionMatchers() {
|
||||
if (this.exceptionMatchers instanceof ImmutableList) {
|
||||
return this.exceptionMatchers;
|
||||
} else {
|
||||
throw new IllegalStateException("Lists haven't been sealed yet.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the expected parameter count for this method.
|
||||
*
|
||||
* @return Expected parameter count, or NULL if anyting goes.
|
||||
*/
|
||||
public Integer getParamCount() {
|
||||
return this.paramCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(MethodInfo value, Object parent) {
|
||||
if (super.isMatch(value, parent)) {
|
||||
// check the return type first (the easiest check)
|
||||
if (!this.returnMatcher.isMatch(value.getReturnType(), value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check for the parameter types
|
||||
Class<?>[] params = value.getParameterTypes();
|
||||
if ((this.paramCount != null) && (this.paramCount != params.length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check parameters and exceptions
|
||||
return this.matchTypes(params, value, this.paramMatchers)
|
||||
&& this.matchTypes(value.getExceptionTypes(), value, this.exceptionMatchers);
|
||||
}
|
||||
|
||||
// No match
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean matchTypes(Class<?>[] types, MethodInfo parent, List<ParameterClassMatcher> matchers) {
|
||||
if (matchers.isEmpty()) {
|
||||
// no matchers - no show
|
||||
return true;
|
||||
}
|
||||
|
||||
// the amount of matchers which are ok with the parameter types
|
||||
int acceptingMatchers = 0;
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (this.processValue(types[i], parent, i, matchers)) {
|
||||
acceptingMatchers++;
|
||||
// if all matchers accepted one type we are done
|
||||
if (acceptingMatchers == matchers.size()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean processValue(Class<?> value, MethodInfo parent, int index, List<ParameterClassMatcher> matchers) {
|
||||
// The order matters
|
||||
for (ParameterClassMatcher matcher : matchers) {
|
||||
// See if we got jackpot
|
||||
if (matcher.isParameterMatch(value, parent, index)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Failure
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> getKeyValueView() {
|
||||
Map<String, Object> member = super.getKeyValueView();
|
||||
|
||||
// Only add fields that are actual constraints
|
||||
if (this.returnMatcher != ClassTypeMatcher.MATCH_ALL) {
|
||||
member.put("return", this.returnMatcher);
|
||||
}
|
||||
|
||||
if (!this.paramMatchers.isEmpty()) {
|
||||
member.put("params", this.paramMatchers);
|
||||
}
|
||||
|
||||
if (!this.exceptionMatchers.isEmpty()) {
|
||||
member.put("exceptions", this.exceptionMatchers);
|
||||
}
|
||||
|
||||
if (this.paramCount != null) {
|
||||
member.put("paramCount", this.paramCount);
|
||||
}
|
||||
|
||||
return member;
|
||||
}
|
||||
|
||||
private static final class ParameterClassMatcher implements AbstractFuzzyMatcher<Class<?>[]> {
|
||||
|
||||
/**
|
||||
* The expected index.
|
||||
*/
|
||||
private final AbstractFuzzyMatcher<Class<?>> typeMatcher;
|
||||
private final Integer indexMatch;
|
||||
|
||||
/**
|
||||
* Construct a new parameter class matcher.
|
||||
*
|
||||
* @param typeMatcher - class type matcher.
|
||||
*/
|
||||
public ParameterClassMatcher(@Nonnull AbstractFuzzyMatcher<Class<?>> typeMatcher) {
|
||||
this(typeMatcher, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new parameter class matcher.
|
||||
*
|
||||
* @param typeMatcher - class type matcher.
|
||||
* @param indexMatch - parameter index to match, or NULL for anything.
|
||||
*/
|
||||
public ParameterClassMatcher(@Nonnull AbstractFuzzyMatcher<Class<?>> typeMatcher, Integer indexMatch) {
|
||||
this.typeMatcher = typeMatcher;
|
||||
this.indexMatch = indexMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* See if there's a match for this matcher.
|
||||
*
|
||||
* @param param - the type to match.
|
||||
* @param parent - the container (member) that holds a reference to this parameter.
|
||||
* @param index - the index of the current parameter.
|
||||
* @return TRUE if this matcher matches any of the given parameters, FALSE otherwise.
|
||||
*/
|
||||
public boolean isParameterMatch(Class<?> param, MethodInfo parent, int index) {
|
||||
// Make sure the index is valid (or NULL)
|
||||
if ((this.indexMatch == null) || (this.indexMatch == index)) {
|
||||
return this.typeMatcher.isMatch(param, parent);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMatch(Class<?>[] value, Object parent) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{ Parameter Type: %s, Index: %s }", this.typeMatcher, this.indexMatch);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a builder for a fuzzy method contract.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public static final class Builder extends AbstractFuzzyMember.Builder<FuzzyMethodContract> {
|
||||
|
||||
@Override
|
||||
public Builder requireModifier(int modifier) {
|
||||
super.requireModifier(modifier);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder requirePublic() {
|
||||
super.requirePublic();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder banModifier(int modifier) {
|
||||
super.banModifier(modifier);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder nameRegex(String regex) {
|
||||
super.nameRegex(regex);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder nameRegex(Pattern pattern) {
|
||||
super.nameRegex(pattern);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder nameExact(String name) {
|
||||
super.nameExact(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder declaringClassExactType(Class<?> declaringClass) {
|
||||
super.declaringClassExactType(declaringClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder declaringClassSuperOf(Class<?> declaringClass) {
|
||||
super.declaringClassSuperOf(declaringClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder declaringClassDerivedOf(Class<?> declaringClass) {
|
||||
super.declaringClassDerivedOf(declaringClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder declaringClassMatching(AbstractFuzzyMatcher<Class<?>> classMatcher) {
|
||||
super.declaringClassMatching(classMatcher);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new required parameter by type for any matching method.
|
||||
*
|
||||
* @param type - the exact type this parameter must match.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterExactType(Class<?> type) {
|
||||
this.member.paramMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchExact(type)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new required parameter whose type must be a superclass of the given type.
|
||||
* <p>
|
||||
* If a method parameter is of type Number, then any derived class here (Integer, Long, etc.) will match it.
|
||||
*
|
||||
* @param type - a type or less derived type of the matching parameter.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterSuperOf(Class<?> type) {
|
||||
this.member.paramMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchSuper(type)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new required parameter whose type must be a derived class of the given class.
|
||||
* <p>
|
||||
* If the method parameter has the type Integer, then the class Number here will match it.
|
||||
*
|
||||
* @param type - a type or more derived type of the matching parameter.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterDerivedOf(Class<?> type) {
|
||||
this.member.paramMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchDerived(type)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new required parameter whose type must match the given class matcher.
|
||||
*
|
||||
* @param classMatcher - the class matcher.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterMatches(AbstractFuzzyMatcher<Class<?>> classMatcher) {
|
||||
this.member.paramMatchers.add(new ParameterClassMatcher(classMatcher));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new required parameter by type and position for any matching method.
|
||||
*
|
||||
* @param type - the exact type this parameter must match.
|
||||
* @param index - the expected position in the parameter list.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterExactType(Class<?> type, int index) {
|
||||
this.member.paramMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchExact(type), index));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new required parameters by type and order for any matching method.
|
||||
*
|
||||
* @param types - the types of every parameters in order.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterExactArray(Class<?>... types) {
|
||||
this.parameterCount(types.length);
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
this.parameterExactType(types[i], i);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new required parameter whose type must be a superclass of the given type.
|
||||
* <p>
|
||||
* If a parameter is of type Number, any derived class (Integer, Long, etc.) will match it.
|
||||
*
|
||||
* @param type - a type or derived type of the matching parameter.
|
||||
* @param index - the expected position in the parameter list.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterSuperOf(Class<?> type, int index) {
|
||||
this.member.paramMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchSuper(type), index));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new required parameter whose type must be a derived class of the given class.
|
||||
* <p>
|
||||
* If the method parameter has the type Integer, then the class Number here will match it.
|
||||
*
|
||||
* @param type - a type or more derived type of the matching parameter.
|
||||
* @param index - the expected position in the parameter list.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterDerivedOf(Class<?> type, int index) {
|
||||
this.member.paramMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchDerived(type), index));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new required parameter whose type must match the given class matcher and index.
|
||||
*
|
||||
* @param classMatcher - the class matcher.
|
||||
* @param index - the expected position in the parameter list.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterMatches(AbstractFuzzyMatcher<Class<?>> classMatcher, int index) {
|
||||
this.member.paramMatchers.add(new ParameterClassMatcher(classMatcher, index));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expected number of parameters in the matching method.
|
||||
*
|
||||
* @param expectedCount - the number of parameters to expect.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder parameterCount(int expectedCount) {
|
||||
this.member.paramCount = expectedCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require a void method.
|
||||
*
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder returnTypeVoid() {
|
||||
return this.returnTypeExact(Void.TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the return type of a matching method exactly.
|
||||
*
|
||||
* @param type - the exact return type.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder returnTypeExact(Class<?> type) {
|
||||
this.member.returnMatcher = FuzzyMatchers.matchExact(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expected super class of the return type for every matching method.
|
||||
*
|
||||
* @param type - the return type, or a super class of it.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder returnDerivedOf(Class<?> type) {
|
||||
this.member.returnMatcher = FuzzyMatchers.matchDerived(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a matcher that must match the return type of a matching method.
|
||||
*
|
||||
* @param classMatcher - the exact return type.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder returnTypeMatches(AbstractFuzzyMatcher<Class<?>> classMatcher) {
|
||||
this.member.returnMatcher = classMatcher;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a throwable exception that must match the given type exactly.
|
||||
*
|
||||
* @param type - exception type.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder exceptionExactType(Class<?> type) {
|
||||
this.member.exceptionMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchExact(type)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a throwable exception that must match the given type or be derived.
|
||||
*
|
||||
* @param type - exception type.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder exceptionSuperOf(Class<?> type) {
|
||||
this.member.exceptionMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchSuper(type)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a throwable exception that must match the given matcher,
|
||||
*
|
||||
* @param classMatcher - the class matcher that must match.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder exceptionMatches(AbstractFuzzyMatcher<Class<?>> classMatcher) {
|
||||
this.member.exceptionMatchers.add(new ParameterClassMatcher(classMatcher));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a throwable exception that must match the given type exactly and index.
|
||||
*
|
||||
* @param type - exception type.
|
||||
* @param index - the position in the throwable list.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder exceptionExactType(Class<?> type, int index) {
|
||||
this.member.exceptionMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchExact(type), index));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a throwable exception that must match the given type or be derived and index.
|
||||
*
|
||||
* @param type - exception type.
|
||||
* @param index - the position in the throwable list.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder exceptionSuperOf(Class<?> type, int index) {
|
||||
this.member.exceptionMatchers.add(new ParameterClassMatcher(FuzzyMatchers.matchSuper(type), index));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a throwable exception that must match the given matcher and index.
|
||||
*
|
||||
* @param classMatcher - the class matcher that must match.
|
||||
* @param index - the position in the throwable list.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public Builder exceptionMatches(AbstractFuzzyMatcher<Class<?>> classMatcher, int index) {
|
||||
this.member.exceptionMatchers.add(new ParameterClassMatcher(classMatcher, index));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
protected FuzzyMethodContract initialMember() {
|
||||
// With mutable lists
|
||||
return new FuzzyMethodContract();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FuzzyMethodContract build() {
|
||||
this.member.prepareBuild();
|
||||
return immutableCopy(this.member);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +1,89 @@
|
||||
package com.github.joelgodofwar.mmh.enums;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public enum CatHeads {
|
||||
ALL_BLACK(
|
||||
"Black Cat", "cat.all_black",
|
||||
"f89934e4-99a0-4dab-9151-7b63831e5fd1", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTA2NGYzN2IxYjVhZDRhMjQ5M2Q4ZmM5ZWJmYzYxYzNkMzUxNTBlNjkxNzc5NzZjNjJjM2U1YjhjNzg0YmY5NiJ9fX0="
|
||||
),
|
||||
"f89934e4-99a0-4dab-9151-7b63831e5fd1", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTA2NGYzN2IxYjVhZDRhMjQ5M2Q4ZmM5ZWJmYzYxYzNkMzUxNTBlNjkxNzc5NzZjNjJjM2U1YjhjNzg0YmY5NiJ9fX0="
|
||||
),
|
||||
BLACK(//used for unknown player heads
|
||||
"Tuxedo Cat", "cat.black",
|
||||
"f0db2cac-dde4-47de-9c27-c001aee27712", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTk2NmI5MDVmODFlZjk1MmI2NjEwZjNhMGJiZDY1NDdiMmYyY2QzNDQ3ZTFmYzgyZDkwNDI5OWJkNjI5NGY4YSJ9fX0="
|
||||
),
|
||||
BRITISH_SHORTHAIR(//used for unknown player heads
|
||||
"f0db2cac-dde4-47de-9c27-c001aee27712", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTk2NmI5MDVmODFlZjk1MmI2NjEwZjNhMGJiZDY1NDdiMmYyY2QzNDQ3ZTFmYzgyZDkwNDI5OWJkNjI5NGY4YSJ9fX0="
|
||||
),
|
||||
BRITISH_SHORTHAIR(//used for unknown player heads
|
||||
"British Shorthair Cat", "cat.british_shorthair",
|
||||
"4332ff48-8a0e-4164-ae55-2d16caf68190", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjNiYjEzNzhlM2ExMDA5ZGViMWIyYTc2YThkNmYwMDljNDZkMGEwMDgwZWVjYjBjM2QyYjRmNjE3Nzc5YzRhYyJ9fX0="
|
||||
),
|
||||
CALICO(//used for unknown player heads
|
||||
"4332ff48-8a0e-4164-ae55-2d16caf68190", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjNiYjEzNzhlM2ExMDA5ZGViMWIyYTc2YThkNmYwMDljNDZkMGEwMDgwZWVjYjBjM2QyYjRmNjE3Nzc5YzRhYyJ9fX0="
|
||||
),
|
||||
CALICO(//used for unknown player heads
|
||||
"Calico Cat", "cat.calico",
|
||||
"024560fb-84a5-40cf-b6a1-c8f9d9db2fe9", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWRhNTI3MTVjMDZmNTQ2ZmRkMTZlZjdhMjllZTc5YzBjZjIxZjEwYzI5ODU4NTgxZDVmYWJlMmY0MzQ5M2E2MSJ9fX0="
|
||||
),
|
||||
JELLIE(//used for unknown player heads
|
||||
"024560fb-84a5-40cf-b6a1-c8f9d9db2fe9", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWRhNTI3MTVjMDZmNTQ2ZmRkMTZlZjdhMjllZTc5YzBjZjIxZjEwYzI5ODU4NTgxZDVmYWJlMmY0MzQ5M2E2MSJ9fX0="
|
||||
),
|
||||
JELLIE(//used for unknown player heads
|
||||
"Jellie Cat", "cat.jellie",
|
||||
"f0aaa05b-0283-4663-9b57-52dbf2ca2750", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2I3MWE3MjYxNTc2NmQ3YzQ2YTliMzYwNTc0NWIxZmIzZjkxYjg0NzBmYmJlYmI2YjNmNmY0OTYyYTk5YzRkNCJ9fX0="
|
||||
),
|
||||
PERSIAN(//used for unknown player heads
|
||||
"f0aaa05b-0283-4663-9b57-52dbf2ca2750", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2I3MWE3MjYxNTc2NmQ3YzQ2YTliMzYwNTc0NWIxZmIzZjkxYjg0NzBmYmJlYmI2YjNmNmY0OTYyYTk5YzRkNCJ9fX0="
|
||||
),
|
||||
PERSIAN(//used for unknown player heads
|
||||
"Persian Cat", "cat.persian",
|
||||
"701fa2a8-ef2b-46cd-b9d3-6cd16be17bb4", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWVkMDI5YTRjMDI3MDIwZDJmZjQ3NTQ0ZTQwYTQ0OTkyM2QyODljZjQ0ZjIyOWRjNzM2ZDNhMTQ1YmMzYTE3NyJ9fX0="
|
||||
),
|
||||
RAGDOLL(//used for unknown player heads
|
||||
"701fa2a8-ef2b-46cd-b9d3-6cd16be17bb4", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWVkMDI5YTRjMDI3MDIwZDJmZjQ3NTQ0ZTQwYTQ0OTkyM2QyODljZjQ0ZjIyOWRjNzM2ZDNhMTQ1YmMzYTE3NyJ9fX0="
|
||||
),
|
||||
RAGDOLL(//used for unknown player heads
|
||||
"Ragdoll Cat", "cat.ragdoll",
|
||||
"b65e722b-5a35-4561-a8df-db9c7a52041f", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmY3NDM1YzIwZWJjNDE0N2YyNmQzYzY1NjQxOTU5YzljYWI0ZGFjOTZiNzMwZjlmNTQyNTVlNzgxY2VlNTMxYSJ9fX0="
|
||||
),
|
||||
RED(//used for unknown player heads
|
||||
"b65e722b-5a35-4561-a8df-db9c7a52041f", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmY3NDM1YzIwZWJjNDE0N2YyNmQzYzY1NjQxOTU5YzljYWI0ZGFjOTZiNzMwZjlmNTQyNTVlNzgxY2VlNTMxYSJ9fX0="
|
||||
),
|
||||
RED(//used for unknown player heads
|
||||
"Red Cat", "cat.red",
|
||||
"11d2442b-0bc1-4475-a499-f07dcc2aa40d", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjM3ZmEwYWJiMjY0ZmRlY2FmN2U5ODQ4MmNkNzgyNGU4ODlkNmQ2NjdlYjc1NDlmMmNhNDk1NDQyZmNlNGEwOCJ9fX0="
|
||||
),
|
||||
SIAMESE(//used for unknown player heads
|
||||
"11d2442b-0bc1-4475-a499-f07dcc2aa40d", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjM3ZmEwYWJiMjY0ZmRlY2FmN2U5ODQ4MmNkNzgyNGU4ODlkNmQ2NjdlYjc1NDlmMmNhNDk1NDQyZmNlNGEwOCJ9fX0="
|
||||
),
|
||||
SIAMESE(//used for unknown player heads
|
||||
"Siamese Cat", "cat.siamese",
|
||||
"7d487214-5276-49af-bbb1-019b49384d69", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2U0OTBiNjEwY2RkZmUyMDA0ODM3ZTFhNzFjOTkxZGQ5NGQ1ZGIxNWZkZTk5ZGVkNWY5MDM3YTdkZWZkMGQwZSJ9fX0="
|
||||
),
|
||||
TABBY(//used for unknown player heads
|
||||
"7d487214-5276-49af-bbb1-019b49384d69", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2U0OTBiNjEwY2RkZmUyMDA0ODM3ZTFhNzFjOTkxZGQ5NGQ1ZGIxNWZkZTk5ZGVkNWY5MDM3YTdkZWZkMGQwZSJ9fX0="
|
||||
),
|
||||
TABBY(//used for unknown player heads
|
||||
"Tabby Cat", "cat.tabby",
|
||||
"18d071ee-a17c-46eb-866c-304a4823ac05", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTgyOTEzMGEyOTM1ZTM5N2M5ZjIxZWRmZWRjNjg5NzNjNzljNGE2Yjc4Njg0ZjQyYjhmNGU2NmUwNGY1NzIyMyJ9fX0="
|
||||
),
|
||||
WHITE(//used for unknown player heads
|
||||
"18d071ee-a17c-46eb-866c-304a4823ac05", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTgyOTEzMGEyOTM1ZTM5N2M5ZjIxZWRmZWRjNjg5NzNjNzljNGE2Yjc4Njg0ZjQyYjhmNGU2NmUwNGY1NzIyMyJ9fX0="
|
||||
),
|
||||
WHITE(//used for unknown player heads
|
||||
"White Cat", "cat.white",
|
||||
"db9474c0-f11e-47d3-a6dc-2ebcdd5f37e0", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGRiOTE2YTA3NTg0MDRkMTIzZjNlZTE3YTZiNzUxNmIxMzg3N2YyODFkOTEwNmM0NDA1NWY0MmY0OTUxOTY2MSJ9fX0="
|
||||
),
|
||||
;
|
||||
private final UUID owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
CatHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
this.name = name;
|
||||
this.owner = UUID.fromString(ownerUUID);
|
||||
this.texture = texture;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(CatHeads cathead : CatHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(cathead.getTexture().contains(texture) )
|
||||
return cathead.getNameString() ;
|
||||
}
|
||||
"db9474c0-f11e-47d3-a6dc-2ebcdd5f37e0", // UUID
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGRiOTE2YTA3NTg0MDRkMTIzZjNlZTE3YTZiNzUxNmIxMzg3N2YyODFkOTEwNmM0NDA1NWY0MmY0OTUxOTY2MSJ9fX0="
|
||||
),
|
||||
;
|
||||
private final String owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
CatHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
this.name = name;
|
||||
this.owner = ownerUUID;
|
||||
this.texture = texture;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(CatHeads cathead : CatHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(cathead.getTexture().contains(texture) ) {
|
||||
return cathead.getNameString() ;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
@@ -95,7 +94,7 @@ public enum CatHeads {
|
||||
/**
|
||||
* @return the owner
|
||||
*/
|
||||
public UUID getOwner() {
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@@ -105,7 +104,7 @@ public enum CatHeads {
|
||||
public String getTexture() {
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
|
||||
@@ -1,80 +1,79 @@
|
||||
package com.github.joelgodofwar.mmh.enums;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public enum HorseHeads {
|
||||
HORSE(
|
||||
"Horse", "horse",
|
||||
"dc1293f0-c0cb-4a1e-973f-bd36d70a3de9",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWRlMTYwNDQ0ODVkMzQwOWE2ZTg4MmJjOWM5MDRjNDQyNWI5Mjg4YWFjZTYwMzg4NWQ1NGM1YWRjNWM3ZWVjYyJ9fX0="
|
||||
),
|
||||
HORSE_BLACK(
|
||||
"Black Horse", "horse.black",
|
||||
"4083cd58-1325-4bfa-9efb-5b8b93a02493",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjIxZjE0ZjU4ZmRmMWM0OGU0YzI4YWZiZWI0YzY4YmE4MGJhMTc1MDVlNTYwYjUwNTk0NTdjN2I3MWMyM2EzZiJ9fX0="
|
||||
),
|
||||
HORSE_BROWN(
|
||||
"Brown Horse", "horse.brown",
|
||||
"2dcb4f55-ab85-48ba-b7d2-7b57d3ec7bfa",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjI1OWUwOWRjYzMwMTg3OTY1YWQxZmZkODRhM2ZjMWQ2ODZhMGQxMTI0NDFiMjA4NWZlNGIxNjMxMWY4OTE1NCJ9fX0="
|
||||
),
|
||||
HORSE_CHESTNUT(
|
||||
"Chestnut Horse", "horse.chestnut",
|
||||
"5a2546e1-2213-4f2a-8cbe-5ffddf3e7269",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTExMzFhZTlmNmNmNzk1NjBlMDgzMjY4Mjc1MTE0NTdjOTljMjg2NmJmYTI1ZDY4Mjg0ZDRhMTY3OWMzZTYyNiJ9fX0="
|
||||
),
|
||||
HORSE_CREAMY(
|
||||
"Creamy Horse", "horse.creamy",
|
||||
"65e8bd32-6f48-4b92-ab48-fe1add6b67d1",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDhjNjRlMTQ5Mzg5Y2JmNTliZTIzNzkyZjE4YWMzOTkxNDI2NThmN2QyZTY2NGY3NTE0N2NhN2FjMjlkODE5OCJ9fX0="
|
||||
),
|
||||
HORSE_DARK_BROWN(
|
||||
"Dark Brown Horse", "horse.dark_brown",
|
||||
"c6abc94e-a5ff-45fe-a0d7-4e479f290a6f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTVkZjI4MGJmYjI0YmFjZDA2YzJlZjU3OWMxNDlhYTVmZDNkNzIzZWY2NWZhNmE5M2I4MzM0YjdmMjkxMzU5YSJ9fX0="
|
||||
),
|
||||
HORSE_GRAY(
|
||||
"Gray Horse", "horse.gray",
|
||||
"b600f9c3-9c3f-4e3c-828c-3ebb6414eaa7",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWNlZGNmOTNmY2ZhYWEwZWQ1OThjNTA5YmZhNmY2ODFjYTIyYzc4MGVmYTFmNDA3ZjBlYTlmOTkxNzE4YWVjMiJ9fX0="
|
||||
),
|
||||
HORSE_WHITE(
|
||||
"White Horse", "horse.white",
|
||||
"d941cb68-8842-4f78-bdf8-5f1d3c6e7ac0",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGE3MWFiNTMwZGY4ZGZjZmQ2MjljODFkMDFlNjU0YTEyZTcyN2VmYjY1YzU1YzkwNjg1ODliOTE2MDgzNGU1ZCJ9fX0="
|
||||
),
|
||||
;
|
||||
|
||||
private final UUID owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
|
||||
HorseHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
this.owner = UUID.fromString(ownerUUID);
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(HorseHeads verbosity : HorseHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) )
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
"dc1293f0-c0cb-4a1e-973f-bd36d70a3de9",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWRlMTYwNDQ0ODVkMzQwOWE2ZTg4MmJjOWM5MDRjNDQyNWI5Mjg4YWFjZTYwMzg4NWQ1NGM1YWRjNWM3ZWVjYyJ9fX0="
|
||||
),
|
||||
HORSE_BLACK(
|
||||
"Black Horse", "horse.black",
|
||||
"4083cd58-1325-4bfa-9efb-5b8b93a02493",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjIxZjE0ZjU4ZmRmMWM0OGU0YzI4YWZiZWI0YzY4YmE4MGJhMTc1MDVlNTYwYjUwNTk0NTdjN2I3MWMyM2EzZiJ9fX0="
|
||||
),
|
||||
HORSE_BROWN(
|
||||
"Brown Horse", "horse.brown",
|
||||
"2dcb4f55-ab85-48ba-b7d2-7b57d3ec7bfa",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjI1OWUwOWRjYzMwMTg3OTY1YWQxZmZkODRhM2ZjMWQ2ODZhMGQxMTI0NDFiMjA4NWZlNGIxNjMxMWY4OTE1NCJ9fX0="
|
||||
),
|
||||
HORSE_CHESTNUT(
|
||||
"Chestnut Horse", "horse.chestnut",
|
||||
"5a2546e1-2213-4f2a-8cbe-5ffddf3e7269",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTExMzFhZTlmNmNmNzk1NjBlMDgzMjY4Mjc1MTE0NTdjOTljMjg2NmJmYTI1ZDY4Mjg0ZDRhMTY3OWMzZTYyNiJ9fX0="
|
||||
),
|
||||
HORSE_CREAMY(
|
||||
"Creamy Horse", "horse.creamy",
|
||||
"65e8bd32-6f48-4b92-ab48-fe1add6b67d1",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDhjNjRlMTQ5Mzg5Y2JmNTliZTIzNzkyZjE4YWMzOTkxNDI2NThmN2QyZTY2NGY3NTE0N2NhN2FjMjlkODE5OCJ9fX0="
|
||||
),
|
||||
HORSE_DARK_BROWN(
|
||||
"Dark Brown Horse", "horse.dark_brown",
|
||||
"c6abc94e-a5ff-45fe-a0d7-4e479f290a6f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTVkZjI4MGJmYjI0YmFjZDA2YzJlZjU3OWMxNDlhYTVmZDNkNzIzZWY2NWZhNmE5M2I4MzM0YjdmMjkxMzU5YSJ9fX0="
|
||||
),
|
||||
HORSE_GRAY(
|
||||
"Gray Horse", "horse.gray",
|
||||
"b600f9c3-9c3f-4e3c-828c-3ebb6414eaa7",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWNlZGNmOTNmY2ZhYWEwZWQ1OThjNTA5YmZhNmY2ODFjYTIyYzc4MGVmYTFmNDA3ZjBlYTlmOTkxNzE4YWVjMiJ9fX0="
|
||||
),
|
||||
HORSE_WHITE(
|
||||
"White Horse", "horse.white",
|
||||
"d941cb68-8842-4f78-bdf8-5f1d3c6e7ac0",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGE3MWFiNTMwZGY4ZGZjZmQ2MjljODFkMDFlNjU0YTEyZTcyN2VmYjY1YzU1YzkwNjg1ODliOTE2MDgzNGU1ZCJ9fX0="
|
||||
),
|
||||
;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
private final String owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
|
||||
HorseHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
this.owner = ownerUUID;
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(HorseHeads verbosity : HorseHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) ) {
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the owner
|
||||
*/
|
||||
public UUID getOwner() {
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@@ -91,7 +90,7 @@ public enum HorseHeads {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
|
||||
@@ -1,100 +1,99 @@
|
||||
package com.github.joelgodofwar.mmh.enums;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public enum LlamaHeads {
|
||||
LLAMA_BROWN(
|
||||
"Brown Llama", "llama.brown",
|
||||
"75fb08e5-2419-46fa-bf09-57362138f234",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjgxNmVmOWRiNzUzNDg4ODNhZTgwMWI5Mzg2YzhlZDM2N2YzYjhkMGMzYmEwMTY3NjYyZGNhZjliMGU4MzkxMiJ9fX0="
|
||||
),
|
||||
LLAMA_CREAMY(
|
||||
"Creamy Llama", "llama.creamy",
|
||||
"dd0a3919-e919-428c-9298-6dcc416fec9d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTA3ZDAyYjgyNWQ0YTQ3NmQ3OGFmNjA3ODU0MWJkZDBmY2I2ODJiMGI0MDk4YjkxYTMxNGUxYjFjNGUzYzRlMSJ9fX0="
|
||||
),
|
||||
LLAMA_GRAY(
|
||||
"Gray Llama", "llama.gray",
|
||||
"edca7a0d-770f-43d6-8ffc-f6a00e94e477",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTYxMjNiMzA0NzE0ZDIzZDExNGRmZTY3Nzk0NmRjYmU0ZmVlODYzNWMwZDAyMTdiODg0NmQxOTM3ODM1ZTZjYiJ9fX0="
|
||||
),
|
||||
LLAMA_WHITE(
|
||||
"White Llama", "llama.white",
|
||||
"60d7893f-b634-48b8-8d6e-f07fa14f5115",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWZhNTgzNmQ5MTk3YTQwNGJiNzJkN2ZiYmVlY2NmOWE0MTQzYzQ1MWVjODQ0NTUzNTUyMTU5ZWQzNjdhNTYxMCJ9fX0="
|
||||
),
|
||||
TRADER_LLAMA_BROWN(
|
||||
"Brown Trader Llama", "trader_llama.brown",
|
||||
"a957be18-324a-4984-a81b-f556a793a64a",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQyNDc4MGIzYzVjNTM1MWNmNDlmYjViZjQxZmNiMjg5NDkxZGY2YzQzMDY4M2M4NGQ3ODQ2MTg4ZGI0Zjg0ZCJ9fX0="
|
||||
),
|
||||
TRADER_LLAMA_CREAMY(
|
||||
"Creamy Trader Llama", "trader_llama.creamy",
|
||||
"75fb08e5-2419-46fa-bf09-57362138f234",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjgxNmVmOWRiNzUzNDg4ODNhZTgwMWI5Mzg2YzhlZDM2N2YzYjhkMGMzYmEwMTY3NjYyZGNhZjliMGU4MzkxMiJ9fX0="
|
||||
),
|
||||
LLAMA_CREAMY(
|
||||
"Creamy Llama", "llama.creamy",
|
||||
"dd0a3919-e919-428c-9298-6dcc416fec9d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTA3ZDAyYjgyNWQ0YTQ3NmQ3OGFmNjA3ODU0MWJkZDBmY2I2ODJiMGI0MDk4YjkxYTMxNGUxYjFjNGUzYzRlMSJ9fX0="
|
||||
),
|
||||
LLAMA_GRAY(
|
||||
"Gray Llama", "llama.gray",
|
||||
"edca7a0d-770f-43d6-8ffc-f6a00e94e477",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTYxMjNiMzA0NzE0ZDIzZDExNGRmZTY3Nzk0NmRjYmU0ZmVlODYzNWMwZDAyMTdiODg0NmQxOTM3ODM1ZTZjYiJ9fX0="
|
||||
),
|
||||
LLAMA_WHITE(
|
||||
"White Llama", "llama.white",
|
||||
"60d7893f-b634-48b8-8d6e-f07fa14f5115",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWZhNTgzNmQ5MTk3YTQwNGJiNzJkN2ZiYmVlY2NmOWE0MTQzYzQ1MWVjODQ0NTUzNTUyMTU5ZWQzNjdhNTYxMCJ9fX0="
|
||||
),
|
||||
TRADER_LLAMA_BROWN(
|
||||
"Brown Trader Llama", "trader_llama.brown",
|
||||
"a957be18-324a-4984-a81b-f556a793a64a",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQyNDc4MGIzYzVjNTM1MWNmNDlmYjViZjQxZmNiMjg5NDkxZGY2YzQzMDY4M2M4NGQ3ODQ2MTg4ZGI0Zjg0ZCJ9fX0="
|
||||
),
|
||||
TRADER_LLAMA_CREAMY(
|
||||
"Creamy Trader Llama", "trader_llama.creamy",
|
||||
"b8e21edd-c25b-4673-9602-6671007f5088",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTg5YTJlYjE3NzA1ZmU3MTU0YWIwNDFlNWM3NmEwOGQ0MTU0NmEzMWJhMjBlYTMwNjBlM2VjOGVkYzEwNDEyYyJ9fX0="
|
||||
),
|
||||
TRADER_LLAMA_GRAY(
|
||||
"Gray Trader Llama", "trader_llama.gray",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTg5YTJlYjE3NzA1ZmU3MTU0YWIwNDFlNWM3NmEwOGQ0MTU0NmEzMWJhMjBlYTMwNjBlM2VjOGVkYzEwNDEyYyJ9fX0="
|
||||
),
|
||||
TRADER_LLAMA_GRAY(
|
||||
"Gray Trader Llama", "trader_llama.gray",
|
||||
"34bfbc2b-6c59-47df-8cf6-7457ad15165a",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmU0ZDhhMGJjMTVmMjM5OTIxZWZkOGJlMzQ4MGJhNzdhOThlZTdkOWNlMDA3MjhjMGQ3MzNmMGEyZDYxNGQxNiJ9fX0="
|
||||
),
|
||||
TRADER_LLAMA_WHITE(
|
||||
"White Trader Llama", "trader_llama.white",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmU0ZDhhMGJjMTVmMjM5OTIxZWZkOGJlMzQ4MGJhNzdhOThlZTdkOWNlMDA3MjhjMGQ3MzNmMGEyZDYxNGQxNiJ9fX0="
|
||||
),
|
||||
TRADER_LLAMA_WHITE(
|
||||
"White Trader Llama", "trader_llama.white",
|
||||
"47dbdab5-105f-42bc-9580-c61cee9231f3",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzA4N2E1NTZkNGZmYTk1ZWNkMjg0NGYzNTBkYzQzZTI1NGU1ZDUzNWZhNTk2ZjU0MGQ3ZTc3ZmE2N2RmNDY5NiJ9fX0="
|
||||
),
|
||||
;
|
||||
|
||||
private final UUID owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
|
||||
LlamaHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
//this.material = material;
|
||||
this.owner = UUID.fromString(ownerUUID);
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(LlamaHeads verbosity : LlamaHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) )
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzA4N2E1NTZkNGZmYTk1ZWNkMjg0NGYzNTBkYzQzZTI1NGU1ZDUzNWZhNTk2ZjU0MGQ3ZTc3ZmE2N2RmNDY5NiJ9fX0="
|
||||
),
|
||||
;
|
||||
|
||||
return null;
|
||||
}
|
||||
private final String owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
LlamaHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
//this.material = material;
|
||||
this.owner = ownerUUID;
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(LlamaHeads verbosity : LlamaHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) ) {
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the owner
|
||||
*/
|
||||
public UUID getOwner() {
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the texture
|
||||
*/
|
||||
public String getTexture() {
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
|
||||
@@ -118,7 +118,7 @@ public enum MobHeads {
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTJiYTM0NDE2NjcwNDU0YjFhMjA0OTZmODBiOTM5ODUyOWY0OTAwM2ZjNjEzZWI5MzAyNDhlYTliNWQxYTM5MSJ9fX0="
|
||||
),
|
||||
HOGLIN(
|
||||
"Hoglin", "hoglin", "",
|
||||
"Hoglin", "hoglin", "6ba8c18c-881a-4829-86e6-d641611ad18e",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGE3ZTI4OGUzNTQ0NWI1MjhjNDAxZWJjNzkwZjU1MWY2ZGM3NDkxYzBkZTY2YjYzNjI2YzUxNzU5MWJkNTViNCJ9fX0="
|
||||
),
|
||||
HUSK(
|
||||
@@ -158,7 +158,7 @@ public enum MobHeads {
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTU0NmU0MzZkMTY2YjE3ZjA1MjFiZDg1MzhlYTEzY2Q2ZWUzYjVkZjEwMmViMzJlM2U0MjVjYjI4NWQ0NDA2MyJ9fX0="
|
||||
),
|
||||
PANDA_BROWN(
|
||||
"Drown Panda", "panda.brown", "e19e8aae-3bf4-4c7a-83bc-9a8c9f6ad544",
|
||||
"Brown Panda", "panda.brown", "e19e8aae-3bf4-4c7a-83bc-9a8c9f6ad544",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWQ1ZjZkNjEyNjcyODY3MWI0NGMxYzc3NWY5OTYxNzQyNGUzMzYxMWI1ZDMxYWQyYWNmZjI4MDRlYjk2ZWIwNiJ9fX0="
|
||||
),
|
||||
PANDA_LAZY(
|
||||
@@ -278,11 +278,11 @@ public enum MobHeads {
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTkyYjU1OTcwODVlMzVkYjUzZDliZGEwMDhjYWU3MmIyZjAwY2Q3ZDRjZDhkYzY5ZmYxNzRhNTViNjg5ZTZlIn19fQ=="
|
||||
),
|
||||
STRIDER(
|
||||
"Strider", "strider", "",
|
||||
"Strider", "strider", "9fde30af-3e79-433b-b4af-ae9cc52b0c96",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGQ2OWVlODMxMmNjN2IxY2ZiZDk1ZTQxZTg5NzFiMmIzNjAyY2FmYTExMDJjMWNjODhhZGQ2MTdmMjhjZmM3ZCJ9fX0="
|
||||
),
|
||||
STRIDER_SHIVERING(
|
||||
"Shivering Strider", "strider_shivering", "",
|
||||
"Shivering Strider", "strider_shivering", "d843d702-9a8c-419a-80d5-da6c51a2c006",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjkwYTEyMDI4YjkwYzBkYTFkNGQxN2U2ZmUxYmY1YmNhZjMzZGNmY2Y0ZTVkNTQ5MzkxMDZiMTg2Y2UyMWQ3NiJ9fX0="
|
||||
),
|
||||
TROPICAL_FISH(
|
||||
@@ -342,7 +342,7 @@ public enum MobHeads {
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGQxYWE3ZTNiOTU2NGIzODQ2ZjFkZWExNGYxYjFjY2JmMzk5YmJiMjNiOTUyZGJkN2VlYzQxODAyYTI4OWM5NiJ9fX0="
|
||||
),
|
||||
ZOGLIN(
|
||||
"Zoglin", "zoglin", "",
|
||||
"Zoglin", "zoglin", "746fe686-6785-4584-9fdb-c76ae015af4e",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzY0Y2ZjNjFhYzUyOTUzMzhkZDJmNGZlNjdmYWI2MjhjZWZkOTQ5MjY5OTIzZjE5YTBjNzcxNjRmOGYwMzRiZiJ9fX0="
|
||||
),
|
||||
ZOMBIE(
|
||||
|
||||
@@ -1,80 +1,79 @@
|
||||
package com.github.joelgodofwar.mmh.enums;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public enum RabbitHeads {
|
||||
RABBIT_BLACK(
|
||||
"Black Rabbit", "rabbit.black",
|
||||
"827f5a8f-1cd7-4148-872f-d3c7f424882f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjJiNDI1ZmYyYTIzNmFiMTljYzkzOTcxOTVkYjQwZjhmMTg1YjE5MWM0MGJmNDRiMjZlOTVlYWM5ZmI1ZWZhMyJ9fX0="
|
||||
),
|
||||
RABBIT_BLACK_AND_WHITE(
|
||||
"Black and White Rabbit", "rabbit.black_and_white",
|
||||
"6bafd710-5fa3-4f4d-99cf-ad47fa436e3f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzVmNzJhMjE5NWViZjQxMTdjNTA1NmNmZTJiNzM1N2VjNWJmODMyZWRlMTg1NmE3NzczZWU0MmEwZDBmYjNmMCJ9fX0="
|
||||
),
|
||||
RABBIT_BROWN(
|
||||
"Brown Rabbit", "rabbit.brown",
|
||||
"2186bdc6-55b1-4b44-8a46-3c8a11d40f3d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2ZkNGY4NmNmNzQ3M2ZiYWU5M2IxZTA5MDQ4OWI2NGMwYmUxMjZjN2JiMTZmZmM4OGMwMDI0NDdkNWM3Mjc5NSJ9fX0="
|
||||
),
|
||||
RABBIT_GOLD(
|
||||
"Gold Rabbit", "rabbit.gold",
|
||||
"dacb90db-f547-4b25-b9fd-c2aefc0b07fa",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzY3YjcyMjY1NmZkZWVjMzk5NzRkMzM5NWM1ZTE4YjQ3YzVlMjM3YmNlNWJiY2VkOWI3NTUzYWExNGI1NDU4NyJ9fX0="
|
||||
),
|
||||
RABBIT_SALT_AND_PEPPER(
|
||||
"Salt and Pepper Rabbit", "rabbit.salt_and_pepper",
|
||||
"02703b0c-573f-4042-a91b-659a3981b508",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTIzODUxOWZmMzk4MTViMTZjNDA2MjgyM2U0MzE2MWZmYWFjOTY4OTRmZTA4OGIwMThlNmEyNGMyNmUxODFlYyJ9fX0="
|
||||
),
|
||||
RABBIT_THE_KILLER_BUNNY(
|
||||
"The Killer Bunny", "rabbit.the_killer_bunny",
|
||||
"38b35a02-6ac6-4cbc-b7d6-6a7043640695",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzFkZDc2NzkyOWVmMmZkMmQ0M2U4NmU4NzQ0YzRiMGQ4MTA4NTM0NzEyMDFmMmRmYTE4Zjk2YTY3ZGU1NmUyZiJ9fX0="
|
||||
),
|
||||
RABBIT_WHITE(
|
||||
"White Rabbit", "rabbit.white",
|
||||
"1288e126-41dd-4608-b304-86d84464d5e4",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTU0MmQ3MTYwOTg3MTQ4YTVkOGUyMGU0NjliZDliM2MyYTM5NDZjN2ZiNTkyM2Y1NWI5YmVhZTk5MTg1ZiJ9fX0="
|
||||
),
|
||||
RABBIT_Toast(
|
||||
"Toast", "rabbit.toast",
|
||||
"4e03f384-b31f-4803-8d74-801ecdf78869",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTFhNTdjM2QwYTliMTBlMTNmNjZkZjc0MjAwY2I4YTZkNDg0YzY3MjIyNjgxMmQ3NGUyNWY2YzAyNzQxMDYxNiJ9fX0="
|
||||
),
|
||||
;
|
||||
|
||||
private final UUID owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
|
||||
RabbitHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
this.owner = UUID.fromString(ownerUUID);
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(RabbitHeads verbosity : RabbitHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) )
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjJiNDI1ZmYyYTIzNmFiMTljYzkzOTcxOTVkYjQwZjhmMTg1YjE5MWM0MGJmNDRiMjZlOTVlYWM5ZmI1ZWZhMyJ9fX0="
|
||||
),
|
||||
RABBIT_BLACK_AND_WHITE(
|
||||
"Black and White Rabbit", "rabbit.black_and_white",
|
||||
"6bafd710-5fa3-4f4d-99cf-ad47fa436e3f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzVmNzJhMjE5NWViZjQxMTdjNTA1NmNmZTJiNzM1N2VjNWJmODMyZWRlMTg1NmE3NzczZWU0MmEwZDBmYjNmMCJ9fX0="
|
||||
),
|
||||
RABBIT_BROWN(
|
||||
"Brown Rabbit", "rabbit.brown",
|
||||
"2186bdc6-55b1-4b44-8a46-3c8a11d40f3d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2ZkNGY4NmNmNzQ3M2ZiYWU5M2IxZTA5MDQ4OWI2NGMwYmUxMjZjN2JiMTZmZmM4OGMwMDI0NDdkNWM3Mjc5NSJ9fX0="
|
||||
),
|
||||
RABBIT_GOLD(
|
||||
"Gold Rabbit", "rabbit.gold",
|
||||
"dacb90db-f547-4b25-b9fd-c2aefc0b07fa",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzY3YjcyMjY1NmZkZWVjMzk5NzRkMzM5NWM1ZTE4YjQ3YzVlMjM3YmNlNWJiY2VkOWI3NTUzYWExNGI1NDU4NyJ9fX0="
|
||||
),
|
||||
RABBIT_SALT_AND_PEPPER(
|
||||
"Salt and Pepper Rabbit", "rabbit.salt_and_pepper",
|
||||
"02703b0c-573f-4042-a91b-659a3981b508",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTIzODUxOWZmMzk4MTViMTZjNDA2MjgyM2U0MzE2MWZmYWFjOTY4OTRmZTA4OGIwMThlNmEyNGMyNmUxODFlYyJ9fX0="
|
||||
),
|
||||
RABBIT_THE_KILLER_BUNNY(
|
||||
"The Killer Bunny", "rabbit.the_killer_bunny",
|
||||
"38b35a02-6ac6-4cbc-b7d6-6a7043640695",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzFkZDc2NzkyOWVmMmZkMmQ0M2U4NmU4NzQ0YzRiMGQ4MTA4NTM0NzEyMDFmMmRmYTE4Zjk2YTY3ZGU1NmUyZiJ9fX0="
|
||||
),
|
||||
RABBIT_WHITE(
|
||||
"White Rabbit", "rabbit.white",
|
||||
"1288e126-41dd-4608-b304-86d84464d5e4",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTU0MmQ3MTYwOTg3MTQ4YTVkOGUyMGU0NjliZDliM2MyYTM5NDZjN2ZiNTkyM2Y1NWI5YmVhZTk5MTg1ZiJ9fX0="
|
||||
),
|
||||
RABBIT_Toast(
|
||||
"Toast", "rabbit.toast",
|
||||
"4e03f384-b31f-4803-8d74-801ecdf78869",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTFhNTdjM2QwYTliMTBlMTNmNjZkZjc0MjAwY2I4YTZkNDg0YzY3MjIyNjgxMmQ3NGUyNWY2YzAyNzQxMDYxNiJ9fX0="
|
||||
),
|
||||
;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
private final String owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
|
||||
RabbitHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
this.owner = ownerUUID;
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(RabbitHeads verbosity : RabbitHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) ) {
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the owner
|
||||
*/
|
||||
public UUID getOwner() {
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@@ -91,7 +90,7 @@ public enum RabbitHeads {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
|
||||
@@ -1,125 +1,124 @@
|
||||
package com.github.joelgodofwar.mmh.enums;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public enum SheepHeads {
|
||||
SHEEP_BLACK(
|
||||
"Black Sheep", "sheep.black",
|
||||
"f6801465-fd07-47f9-92a1-3ae921c3ef05",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTMzMzVlODA2NWM3YjVkZmVhNThkM2RmNzQ3NGYzOTZhZjRmYTBhMmJhNTJhM2M5YjdmYmE2ODMxOTI3MWM5MSJ9fX0="
|
||||
),
|
||||
SHEEP_BLUE(
|
||||
"Blue Sheep", "sheep.blue",
|
||||
"dc501290-d6f2-4fc2-a4c3-b4de68fbb395",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzQwZTI3N2RhNmMzOThiNzQ5YTMyZjlkMDgwZjFjZjRjNGVmM2YxZjIwZGQ5ZTVmNDIyNTA5ZTdmZjU5M2MwIn19fQ=="
|
||||
),
|
||||
SHEEP_BROWN(
|
||||
"Brown Sheep", "sheep.brown",
|
||||
"68f33306-b8e2-472b-984e-6a05ecb32d63",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzEyOGQwODZiYzgxNjY5ZmMyMjU1YmIyMmNhZGM2NmEwZjVlZDcwODg1ZTg0YzMyZDM3YzFiNDg0ZGIzNTkwMSJ9fX0="
|
||||
),
|
||||
SHEEP_CYAN(
|
||||
"Cyan Sheep", "sheep.cyan",
|
||||
"6484f6d0-03c5-4c88-b121-c776dd24e6b4",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWQ0MmZjYmNhZjlkNDhmNzNmZmIwYzNjMzZmMzRiNDY0MzI5NWY2ZGFhNmNjNzRhYjlkMjQyZWQ1YWE1NjM2In19fQ=="
|
||||
),
|
||||
SHEEP_GRAY(
|
||||
"Gray Sheep", "sheep.gray",
|
||||
"1ad6a380-fd48-43e0-a7ea-5685072f37b6",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZmVjZjA2MDNiMmRjZDc5ODRkMjUyNTg2MDY5ODk1ZGI5YWE3OGUxODQxYmQ1NTRiMTk1MDhkY2Y5NjdhMSJ9fX0="
|
||||
),
|
||||
SHEEP_GREEN(
|
||||
"Green Sheep", "sheep.green",
|
||||
"710d1cc5-d61c-415b-b4a6-658d1e5652e8",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWVhODg3ZWFlNGIwNzYzNmU5ZTJmOTA2NjA5YjAwYWI4ZDliODZiNzQ3MjhiODE5ZmY2ZjM3NjU4M2VhMTM5In19fQ=="
|
||||
),
|
||||
SHEEP_jeb_(
|
||||
"Jeb_ Sheep", "sheep.jeb_",
|
||||
"9bb1e075-7a09-4bac-a8a4-441ee9184303",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGQxYjAxZmJlOTllOWY3MDA3OTA1YTU3OGYwYTkyMzVmNzM5NjU2NTg2Yzc5ZjFkYmQyMTExZjlhMzliZGMxZCJ9fX0="
|
||||
),
|
||||
SHEEP_LIGHT_BLUE(
|
||||
"Light Blue Sheep", "sheep.light_blue",
|
||||
"f6ad6acf-aabe-45ac-94bb-d67b9dfdcc63",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWJmMjNhZjg3MTljNDM3YjNlZTg0MDE5YmEzYzllNjljYTg1NGQzYThhZmQ1Y2JhNmQ5Njk2YzA1M2I0ODYxNCJ9fX0="
|
||||
),
|
||||
SHEEP_LIGHT_GRAY(
|
||||
"Light Gray Sheep", "sheep.light_gray",
|
||||
"97331797-cf17-4127-b250-4ec2e8cc0608",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWQyZTJlOTNhMTQyYmZkNDNmMjQwZDM3ZGU4ZjliMDk3NmU3NmU2NWIyMjY1MTkwODI1OWU0NmRiNzcwZSJ9fX0="
|
||||
),
|
||||
SHEEP_LIME(
|
||||
"Lime Sheep", "sheep.lime",
|
||||
"2d1afbe7-9651-45f7-bf6e-fa7647ed6a42",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmJlYWQwMzQyYWU4OWI4ZGZkM2Q3MTFhNjBhZGQ2NWUyYzJiZmVhOGQwYmQyNzRhNzU4N2RlZWQ3YTMxODkyZSJ9fX0="
|
||||
),
|
||||
SHEEP_MAGENTA(
|
||||
"Magenta Sheep", "sheep.magenta",
|
||||
"df42f9f2-86ef-488e-874a-7f8438f56d56",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYThlMWYwNWYwZGFjY2E2M2E3MzE4NzRmOTBhNjkzZmZlMjFmZjgzMmUyYjFlMWQwN2I2NWM4NzY0NTI2ZjA4OSJ9fX0="
|
||||
),
|
||||
SHEEP_ORANGE(
|
||||
"Orange Sheep", "sheep.orange",
|
||||
"c1cde30f-88ad-4d05-a278-6dd2bae9a500",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjY4NGQwNGZhODBhYTU5ZGExNDUzNWRlYWQzODgzZDA5N2ZiYmE0MDA2MjU2NTlmNTI1OTk2NDgwNmJhNjZmMCJ9fX0="
|
||||
),
|
||||
SHEEP_PINK(
|
||||
"Pink Sheep", "sheep.pink",
|
||||
"b7df2ea8-b576-4386-8026-7df2af1051f1",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjM2M2U4YTkzZDI4N2E4NGU2NDAzMDlhZTgzY2ExZGUwYTBiMjU3NTA1YTIwZWM1NWIzMzQ5ZDQwYTQ0ODU0In19fQ=="
|
||||
),
|
||||
SHEEP_PURPLE(
|
||||
"Purple Sheep", "sheep.purple",
|
||||
"ff5c1932-8096-4751-bbcf-7e0d8837b8c1",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzQ0OWQwODI5MWRhZTQ1YTI0NjczNjE5NjAyZjQzNWI1N2Y0Y2Q0ZTllOThkMmUwZmJlYzRmMTgxNDQ3ODFkMyJ9fX0="
|
||||
),
|
||||
SHEEP_RED(
|
||||
"Red Sheep", "sheep.red",
|
||||
"b2386bba-3c78-456c-bc90-a9716cec93bd",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTQ3OGUwNTcxNThkZTZmNDVlMjU0MWNkMTc3ODhlNjQwY2NiNTk3MjNkZTU5YzI1NGU4MmFiNTcxMWYzZmMyNyJ9fX0="
|
||||
),
|
||||
SHEEP_WHITE(
|
||||
"White Sheep", "sheep.white",
|
||||
"fa234925-9dbe-4b8f-a544-7c70fb6b6ac5",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmRmZTdjYzQ2ZDc0OWIxNTMyNjFjMWRjMTFhYmJmMmEzMTA4ZWExYmEwYjI2NTAyODBlZWQxNTkyZGNmYzc1YiJ9fX0="
|
||||
),
|
||||
SHEEP_YELLOW(
|
||||
"Yellow Sheep", "sheep.yellow",
|
||||
"f4b4f889-4cdb-458e-8c86-50d91c4c1c89",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTRiMjhmMDM1NzM1OTA2ZjgyZmZjNGRiYTk5YzlmMGI1NTI0MGU0MjZjZDFjNTI1YTlhYTc3MTgwZWVjNDkzNCJ9fX0="
|
||||
),
|
||||
;
|
||||
|
||||
private final UUID owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
|
||||
SheepHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
this.owner = UUID.fromString(ownerUUID);
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(SheepHeads verbosity : SheepHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) )
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
"Black Sheep", "sheep.black",
|
||||
"f6801465-fd07-47f9-92a1-3ae921c3ef05",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTMzMzVlODA2NWM3YjVkZmVhNThkM2RmNzQ3NGYzOTZhZjRmYTBhMmJhNTJhM2M5YjdmYmE2ODMxOTI3MWM5MSJ9fX0="
|
||||
),
|
||||
SHEEP_BLUE(
|
||||
"Blue Sheep", "sheep.blue",
|
||||
"dc501290-d6f2-4fc2-a4c3-b4de68fbb395",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzQwZTI3N2RhNmMzOThiNzQ5YTMyZjlkMDgwZjFjZjRjNGVmM2YxZjIwZGQ5ZTVmNDIyNTA5ZTdmZjU5M2MwIn19fQ=="
|
||||
),
|
||||
SHEEP_BROWN(
|
||||
"Brown Sheep", "sheep.brown",
|
||||
"68f33306-b8e2-472b-984e-6a05ecb32d63",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzEyOGQwODZiYzgxNjY5ZmMyMjU1YmIyMmNhZGM2NmEwZjVlZDcwODg1ZTg0YzMyZDM3YzFiNDg0ZGIzNTkwMSJ9fX0="
|
||||
),
|
||||
SHEEP_CYAN(
|
||||
"Cyan Sheep", "sheep.cyan",
|
||||
"6484f6d0-03c5-4c88-b121-c776dd24e6b4",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWQ0MmZjYmNhZjlkNDhmNzNmZmIwYzNjMzZmMzRiNDY0MzI5NWY2ZGFhNmNjNzRhYjlkMjQyZWQ1YWE1NjM2In19fQ=="
|
||||
),
|
||||
SHEEP_GRAY(
|
||||
"Gray Sheep", "sheep.gray",
|
||||
"1ad6a380-fd48-43e0-a7ea-5685072f37b6",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZmVjZjA2MDNiMmRjZDc5ODRkMjUyNTg2MDY5ODk1ZGI5YWE3OGUxODQxYmQ1NTRiMTk1MDhkY2Y5NjdhMSJ9fX0="
|
||||
),
|
||||
SHEEP_GREEN(
|
||||
"Green Sheep", "sheep.green",
|
||||
"710d1cc5-d61c-415b-b4a6-658d1e5652e8",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWVhODg3ZWFlNGIwNzYzNmU5ZTJmOTA2NjA5YjAwYWI4ZDliODZiNzQ3MjhiODE5ZmY2ZjM3NjU4M2VhMTM5In19fQ=="
|
||||
),
|
||||
SHEEP_jeb_(
|
||||
"Jeb_ Sheep", "sheep.jeb_",
|
||||
"9bb1e075-7a09-4bac-a8a4-441ee9184303",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGQxYjAxZmJlOTllOWY3MDA3OTA1YTU3OGYwYTkyMzVmNzM5NjU2NTg2Yzc5ZjFkYmQyMTExZjlhMzliZGMxZCJ9fX0="
|
||||
),
|
||||
SHEEP_LIGHT_BLUE(
|
||||
"Light Blue Sheep", "sheep.light_blue",
|
||||
"f6ad6acf-aabe-45ac-94bb-d67b9dfdcc63",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWJmMjNhZjg3MTljNDM3YjNlZTg0MDE5YmEzYzllNjljYTg1NGQzYThhZmQ1Y2JhNmQ5Njk2YzA1M2I0ODYxNCJ9fX0="
|
||||
),
|
||||
SHEEP_LIGHT_GRAY(
|
||||
"Light Gray Sheep", "sheep.light_gray",
|
||||
"97331797-cf17-4127-b250-4ec2e8cc0608",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWQyZTJlOTNhMTQyYmZkNDNmMjQwZDM3ZGU4ZjliMDk3NmU3NmU2NWIyMjY1MTkwODI1OWU0NmRiNzcwZSJ9fX0="
|
||||
),
|
||||
SHEEP_LIME(
|
||||
"Lime Sheep", "sheep.lime",
|
||||
"2d1afbe7-9651-45f7-bf6e-fa7647ed6a42",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmJlYWQwMzQyYWU4OWI4ZGZkM2Q3MTFhNjBhZGQ2NWUyYzJiZmVhOGQwYmQyNzRhNzU4N2RlZWQ3YTMxODkyZSJ9fX0="
|
||||
),
|
||||
SHEEP_MAGENTA(
|
||||
"Magenta Sheep", "sheep.magenta",
|
||||
"df42f9f2-86ef-488e-874a-7f8438f56d56",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYThlMWYwNWYwZGFjY2E2M2E3MzE4NzRmOTBhNjkzZmZlMjFmZjgzMmUyYjFlMWQwN2I2NWM4NzY0NTI2ZjA4OSJ9fX0="
|
||||
),
|
||||
SHEEP_ORANGE(
|
||||
"Orange Sheep", "sheep.orange",
|
||||
"c1cde30f-88ad-4d05-a278-6dd2bae9a500",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjY4NGQwNGZhODBhYTU5ZGExNDUzNWRlYWQzODgzZDA5N2ZiYmE0MDA2MjU2NTlmNTI1OTk2NDgwNmJhNjZmMCJ9fX0="
|
||||
),
|
||||
SHEEP_PINK(
|
||||
"Pink Sheep", "sheep.pink",
|
||||
"b7df2ea8-b576-4386-8026-7df2af1051f1",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjM2M2U4YTkzZDI4N2E4NGU2NDAzMDlhZTgzY2ExZGUwYTBiMjU3NTA1YTIwZWM1NWIzMzQ5ZDQwYTQ0ODU0In19fQ=="
|
||||
),
|
||||
SHEEP_PURPLE(
|
||||
"Purple Sheep", "sheep.purple",
|
||||
"ff5c1932-8096-4751-bbcf-7e0d8837b8c1",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzQ0OWQwODI5MWRhZTQ1YTI0NjczNjE5NjAyZjQzNWI1N2Y0Y2Q0ZTllOThkMmUwZmJlYzRmMTgxNDQ3ODFkMyJ9fX0="
|
||||
),
|
||||
SHEEP_RED(
|
||||
"Red Sheep", "sheep.red",
|
||||
"b2386bba-3c78-456c-bc90-a9716cec93bd",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTQ3OGUwNTcxNThkZTZmNDVlMjU0MWNkMTc3ODhlNjQwY2NiNTk3MjNkZTU5YzI1NGU4MmFiNTcxMWYzZmMyNyJ9fX0="
|
||||
),
|
||||
SHEEP_WHITE(
|
||||
"White Sheep", "sheep.white",
|
||||
"fa234925-9dbe-4b8f-a544-7c70fb6b6ac5",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmRmZTdjYzQ2ZDc0OWIxNTMyNjFjMWRjMTFhYmJmMmEzMTA4ZWExYmEwYjI2NTAyODBlZWQxNTkyZGNmYzc1YiJ9fX0="
|
||||
),
|
||||
SHEEP_YELLOW(
|
||||
"Yellow Sheep", "sheep.yellow",
|
||||
"f4b4f889-4cdb-458e-8c86-50d91c4c1c89",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTRiMjhmMDM1NzM1OTA2ZjgyZmZjNGRiYTk5YzlmMGI1NTI0MGU0MjZjZDFjNTI1YTlhYTc3MTgwZWVjNDkzNCJ9fX0="
|
||||
),
|
||||
;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
private final String owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
|
||||
SheepHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
this.owner = ownerUUID;
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(SheepHeads verbosity : SheepHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) ) {
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the owner
|
||||
*/
|
||||
public UUID getOwner() {
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@@ -136,7 +135,7 @@ public enum SheepHeads {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
|
||||
@@ -5,177 +5,180 @@ public enum TropicalFishHeads {
|
||||
"Anemone", "tropical_fish.anemone",
|
||||
"00a90199-6ce0-4564-975e-8290216c8366",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZThkMjc1NThiYTYzYmI2ZTE0MTFmY2ZiYWRjMjMzNzk1N2RjMDBjNjIzYmFlZDEwMWZmOTFlYjVlOGQ3Mzc3ZSJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_BLACK_TANG(
|
||||
|
||||
|
||||
"Black Tang", "tropical_fish.black_tang",
|
||||
"e871a0d2-dbd4-4828-b10a-31e81c1a532c",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWM5MzIzYzk2Y2JkYjhmNzJmYWYyZjMzOTZhZmUxNDc5MjQ2ODUyNTZkZTZlZmZjNDgxOTg5NzhiM2YwMThmYiJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_BLUE_DORY(
|
||||
|
||||
|
||||
"Blue dory", "tropical_fish.blue_dory",
|
||||
"80e99073-7638-4828-8758-ce72259aa1f3",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2IwNDlhNjlhZDJiNGQ4YTVkYWFiODM3MmVlOTEyYzcyOGFjODA5ZjhmZDQxMGNiZTdhMGI4MDU0NmRlOThjYiJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_BLUE_TANG(
|
||||
|
||||
|
||||
"Blue Tang", "tropical_fish.blue_tang",
|
||||
"8efbc759-f464-4439-b5aa-a1556e35473c",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmZkYzlkOTEwODM0NDYxNjkyNTAwMjBkNzU4YWUxMjY5YzMxOTFlY2YwMDIxNWQxYzY2ZTgyOTEzNDY3YTA4MiJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_BUTTERFLYFISH(
|
||||
|
||||
|
||||
"Butterflyfish", "tropical_fish.butterflyfish",
|
||||
"bfc37de1-b659-4ba8-8a54-42c7bcf1e585",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGM1Zjc3ZDkxN2FjZmQzNzEzYzUzNTUyY2FkYmEwNjdmNWI2ZGY3MjM5M2IxYjMwYTJkYzEwODMzZDkxM2NlMiJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_CICHLID(
|
||||
|
||||
|
||||
"Cichlid", "tropical_fish.cichlid",
|
||||
"633754f1-c11b-4f7c-b14e-b544d2317cab",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGNjYWU0MzY2NWYxMjNhODRjZWUzN2Y1MGVlMjQxODc3ZTA1ZGJjZmEyODA5ZWM1OWFjNTdkMGNlZDZmZTc5OSJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_CLOWNFISH(
|
||||
|
||||
|
||||
"Clownfish", "tropical_fish.clownfish",
|
||||
"df0eaa76-2936-452c-bdd8-d1eed124206a",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzYzODlhY2Q3YzgyODBkMmM4MDg1ZTZhNmE5MWUxODI0NjUzNDdjYzg5OGRiOGMyZDliYjE0OGUwMjcxYzNlNSJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_COTTON_CANDY_BETTA(
|
||||
|
||||
|
||||
"Cotton Candy Betta", "tropical_fish.cotton_candy_betta",
|
||||
"e843d41d-5a3f-4183-bc9e-9021b98e3569",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTNkNzc2N2RlN2FjZDlmZTllMDM4MzI1NzRiMjQ4MzQ0ZjBhZTA2ZjRjMWE3YzZjYjVjNGIwOTIzYWVmZTU2ZCJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_DOTTYBACK(
|
||||
|
||||
|
||||
"Dottyback", "tropical_fish.dottyback",
|
||||
"55dcc35d-d6cb-4e91-b110-9f985b5627e9",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWZhMWY1NWFlMWEwMWM1ZGJkMGM2NGIzMTg4OTFjZWJlNmVmMTVjODk2MmNkZTZlMDRjM2E5Njg0ZTg1MjI0NyJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_EMPEROR_RED_SNAPPER(
|
||||
|
||||
|
||||
"Emperor Red Snapper", "tropical_fish.emperor_red_snapper",
|
||||
"f35b0c65-4042-4b5e-8b86-7308518ac531",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjhkNDRiMzNlYWY5YTY4OGYxYzVmMWUwOTM0ZDFmYjQwMzM3NzkxNjk4N2UyMWMzZjNhMDg1ZGI2NmU1ZWYzNyJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_GOATFISH(
|
||||
|
||||
|
||||
"Goatfish", "tropical_fish.goatfish",
|
||||
"a3331d69-5d09-471b-b9c6-50b1cdc6e98b",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWRjNDdiNDBhYzMxMDM0YTZhYzAyOGNlNWU5NmQ2YWUyNzBiNzM5Zjc0MmIzNTU3MmE5OTk0N2I5MzA2YmQ3In19fQ=="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_MOORISH_IDOL(
|
||||
|
||||
|
||||
"Moorish Idol", "tropical_fish.moorish_idol",
|
||||
"995ff86a-934c-4055-a4e6-1674e0a4fdf4",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2UzNDU1Y2RlZTNjODRjYzhiZWY3OWM5MmI1MzZjMjg4OWVhZjhmOTQxMjYxNjFmNmJiZjlkNjNiZTc1OGE1NCJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_ORNATE_BUTTERFLYFISH(
|
||||
|
||||
|
||||
"Ornate Butterflyfish", "tropical_fish.ornate_butterflyfish",
|
||||
"ae3034b3-4dc1-4c25-8b46-81b234cf5a0d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWE0MzQ5ZWIxMmIxMDE5MWUwYzA0Y2EzNDlmZTI2ZjI0MTlkYWNjNWJjMDk1NjllZTlmNjk4ZDAyYWEwNGI4ZSJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_PARROTFISH(
|
||||
|
||||
|
||||
"Parrotfish", "tropical_fish.parrotfish",
|
||||
"02d9385b-a486-4975-8d5b-ada5a7ea6c01",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzViYTM5M2I5MjZlZTY5YTE0ZDRkODUzYjI1ZDI4NWE4NjhiMTZjNTZjOTE5ZDJiODI0NDEzZTY1NjZkNGU1NSJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_QUEEN_ANGELFISH(
|
||||
|
||||
|
||||
"Queen Angelfish", "tropical_fish.queen_angelfish",
|
||||
"7f37ffc4-3ba4-4905-bc6f-2617fa3ba8f9",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWRmYjRkN2RmZjU0NTZkZTcwNDk2NDE0ZTg3NGM2NjUwYTFlODM5NTYzY2M3NWQ0Yjk5MzgwYjIxNmNmZGJjZCJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_RED_CICHLID(
|
||||
|
||||
|
||||
"Red Cichlid", "tropical_fish.red_cichlid",
|
||||
"7cf27041-6a3b-4d2e-b0a2-87d56bbee139",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzM3ZThjYzc2MDYzMDI4Mjc3YjhiOGZkZGNmMTA3MmY4MjZkNmM3MjAyY2IyOTU0ODFiZGU3MGJhYzk1MGY4OCJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_RED_LIPPED_BLENNY(
|
||||
|
||||
|
||||
"Red Lipped Blenny", "tropical_fish.red_lipped_blenny",
|
||||
"574519ee-7185-427e-b006-73268e705829",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjJkMjJiZTEyZTE0NjY0Y2FlM2ZlMjI2ZDFiMzQ4N2VlMmE3ZDhlNzZhMGUyOWJjYTRkYmY5OTY0YjJhMGY2MyJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_RED_SNAPPER(
|
||||
|
||||
|
||||
"Red Snapper", "tropical_fish.red_snapper",
|
||||
"9f2f51a4-7635-43bf-889d-3728342708a6",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmI4MjI2YWI5ODcwYjdjNmM1OWQzMWI0MGI4NmVkZjczMjRlY2E2NzRiNzBkNTViZThhYWU2YTBiODllN2Q4YiJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_THREADFIN(
|
||||
|
||||
|
||||
"Threadfin", "tropical_fish.threadfin",
|
||||
"b5ea6ce5-4bcd-4b8b-b5a0-a65f9a946e24",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzI0NDRkOTA1YTk5MzA0NGFhNTBkZThjNTUwYmI2NTgzYWQ1N2E4ZDE5OWRhMjliOTkxYmVmMDMwYjQ2ZTM3In19fQ=="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_TOMATO_CLOWNFISH(
|
||||
|
||||
|
||||
"Tomato Clownfish", "tropical_fish.tomato_clownfish",
|
||||
"ff8a2a72-c071-4307-8a31-5186949e01f6",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2U5MmYwYjBmNzljN2JhOWRjODE1NzdiZTMzYTVjNzEzZmJlMzk3MjgyNmI0NGJjZjI2ZmViNmNjMTJiNjQzNCJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_TRIGGERFISH(
|
||||
|
||||
|
||||
"Triggerfish", "tropical_fish.triggerfish",
|
||||
"27a63885-df8d-49aa-bfcf-c591d7b99c2d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmMwZDFlNmQyYTlkZjRmMGViYmNkNTQ3NzhmZjMxYjdjMjQ5ZTBkOTk0NGZjZWQ0YjFhODNhZmJhZWVhY2ZjYSJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_YELLOWTAIL_PARROTFISH(
|
||||
|
||||
|
||||
"Yellowtail Parrotfish", "tropical_fish.yellow_parrotfish",
|
||||
"9bb8e0ff-0fdf-49c3-849b-eaf31ad93c63",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWQ3YjkyYTFiZGM3MzNkMmE1M2ZiMDk1YzcwYjczMmI3MWEyMjNhOWNlY2E3MmI4NzJlMWVlOTkwYTZhOTA3ZSJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_YELLOW_TANG(
|
||||
|
||||
|
||||
"Yellow Tang", "tropical_fish.yellow_tang",
|
||||
"e52ecf57-6857-49df-8b20-c9457cb215df",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2IwMjZhYjBmNDcxZjVjNmUzOWM5ZDM1ODViYzg4MjRlOWQxYjVmMzczZDJjYjcwMThlNjE1MDBlMWE5ZWIzYSJ9fX0="
|
||||
),
|
||||
),
|
||||
TROPICAL_FISH_TROPICAL_FISH(
|
||||
"Tropical Fish", "tropical_fish.tropical_fish", "6c2851ca-37b3-4f29-8415-c3d03f32e27d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzRhMGM4NGRjM2MwOTBkZjdiYWZjNDM2N2E5ZmM2Yzg1MjBkYTJmNzNlZmZmYjgwZTkzNGQxMTg5ZWFkYWM0MSJ9fX0="
|
||||
),
|
||||
"Tropical Fish", "tropical_fish.tropical_fish",
|
||||
"6c2851ca-37b3-4f29-8415-c3d03f32e27d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzRhMGM4NGRjM2MwOTBkZjdiYWZjNDM2N2E5ZmM2Yzg1MjBkYTJmNzNlZmZmYjgwZTkzNGQxMTg5ZWFkYWM0MSJ9fX0="
|
||||
),
|
||||
;
|
||||
|
||||
//private final UUID owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
|
||||
TropicalFishHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
//this.owner = UUID.fromString(ownerUUID);
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(RabbitHeads verbosity : RabbitHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) )
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
private final String owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
|
||||
TropicalFishHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
//this.owner = UUID.fromString(ownerUUID);
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.owner = ownerUUID;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(RabbitHeads verbosity : RabbitHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) ) {
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the owner
|
||||
*/
|
||||
/**public UUID getOwner() {
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}//*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the texture
|
||||
@@ -190,7 +193,7 @@ public enum TropicalFishHeads {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
|
||||
@@ -5,463 +5,467 @@ package com.github.joelgodofwar.mmh.enums;
|
||||
|
||||
public enum VillagerHeads {
|
||||
VILLAGER_ARMORER_PLAINS(//
|
||||
"Plains Armorer Villager", "villager.plains.armorer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzMzgyMTc0MjcsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjAxMzExYzUxODUyOWFmNTRhMWMzZWU2M2MzNmQwM2IwNGFjMjFkZmRiNmE5MGM1N2VhOTU0NzhhYWI2MDNlNSJ9fX0="
|
||||
),
|
||||
VILLAGER_BUTCHER_PLAINS(//
|
||||
"Plains Butcher Villager", "villager.plains.butcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDExNDE5OTYsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzFhNzAzZjY0NzA0M2UwY2U5ZjAzYzQyOGQxM2EwYTZmZWY0NWUzMGE3MzMxN2ViMTIxY2ZiZjFmYjg4YzE5NyJ9fX0="
|
||||
),
|
||||
"Plains Armorer Villager", "villager.plains.armorer", "a576057c-02d0-4af9-ae5a-acb4458b4971",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjAxMzExYzUxODUyOWFmNTRhMWMzZWU2M2MzNmQwM2IwNGFjMjFkZmRiNmE5MGM1N2VhOTU0NzhhYWI2MDNlNSJ9fX0="
|
||||
),
|
||||
VILLAGER_BUTCHER_PLAINS(//
|
||||
"Plains Butcher Villager", "villager.plains.butcher", "c25bcd22-83d9-46fa-92ac-145e4681d08d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzFhNzAzZjY0NzA0M2UwY2U5ZjAzYzQyOGQxM2EwYTZmZWY0NWUzMGE3MzMxN2ViMTIxY2ZiZjFmYjg4YzE5NyJ9fX0="
|
||||
),
|
||||
VILLAGER_CARTOGRAPHER_PLAINS(//
|
||||
"Plains Cartographer Villager", "villager.plains.cartographer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDE5OTM4MDAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZhZDhiMGQ0MGIwNTRkNjlhYTI4OTQ5NzQwYmU3NmY4NWU4M2RiMzljMjcyZGU2NzIzYTQzOTJhYmUyMzA1YiJ9fX0="
|
||||
),
|
||||
"Plains Cartographer Villager", "villager.plains.cartographer", "dfa9dc67-8091-4b78-9bbb-00cb4c34cb58",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZhZDhiMGQ0MGIwNTRkNjlhYTI4OTQ5NzQwYmU3NmY4NWU4M2RiMzljMjcyZGU2NzIzYTQzOTJhYmUyMzA1YiJ9fX0="
|
||||
),
|
||||
VILLAGER_CLERIC_PLAINS(//
|
||||
"Plains Cleric Villager", "villager.plains.cleric",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDI2MDI3ODQsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzViNmYxNmQ0NmQ3MmEyMTgwNTE4ZTU5ZWU3Mjc1OWQ5ODYwMmI0YmJkZTA0ZjBhNDk3MjhlYTE1ZjBlMTIifX19"
|
||||
),
|
||||
"Plains Cleric Villager", "villager.plains.cleric", "4130d8bc-7d79-498f-8ead-b9e32a86d4a6",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzViNmYxNmQ0NmQ3MmEyMTgwNTE4ZTU5ZWU3Mjc1OWQ5ODYwMmI0YmJkZTA0ZjBhNDk3MjhlYTE1ZjBlMTIifX19"
|
||||
),
|
||||
VILLAGER_FARMER_PLAINS(//
|
||||
"Plains Farmer Villager", "villager.plains.farmer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDMyOTI3NTEsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2ZkNjQwZjg1Nzg3NTU3NWI1YzhmNzlmY2E5YjM1NGMxNTgwZWJhNTViY2M4MGMzZWY1NzkxNDVhZTFlZDJmNiJ9fX0="
|
||||
),
|
||||
"Plains Farmer Villager", "villager.plains.farmer", "1d307c7a-6e3f-4862-9503-740dd9bb92d9",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2ZkNjQwZjg1Nzg3NTU3NWI1YzhmNzlmY2E5YjM1NGMxNTgwZWJhNTViY2M4MGMzZWY1NzkxNDVhZTFlZDJmNiJ9fX0="
|
||||
),
|
||||
VILLAGER_FISHERMAN_PLAINS(//
|
||||
"Plains Fisherman Villager", "villager.plains.fisherman",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDM5NDc4MjAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTIxMzM4NDRiOGViMjVmODA1NmZiN2IyNWU2YTYwODM0N2Q2ZWY3YmMxYmY4NzZiMzY4ZTlkN2E2MDdhNDMxMyJ9fX0="
|
||||
),
|
||||
"Plains Fisherman Villager", "villager.plains.fisherman", "49ecebb5-0a3c-4e7a-ac18-f7b7c1c6b42b",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTIxMzM4NDRiOGViMjVmODA1NmZiN2IyNWU2YTYwODM0N2Q2ZWY3YmMxYmY4NzZiMzY4ZTlkN2E2MDdhNDMxMyJ9fX0="
|
||||
),
|
||||
VILLAGER_FLETCHER_PLAINS(//
|
||||
"Plains Fletcher Villager", "villager.plains.fletcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDQ5MTUwODUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODIxNTg4ODRlYzQ1YzI2YjA2ZTA0YWM4MDM1NWJjYjViNzYwYjQ2MDkzOTYzODljOTQ4MzA1ZjAzYjNkYWU5ZCJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_PLAINS(//\\
|
||||
"Plains Leatherworker Villager", "villager.plains.leatherworker",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQyNTM3Njc0NzcsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWQ0NDY4YjMzYzE2Mzc1OGUzYmM3Yzk2OTRjODA0YmZmNGY4YTVmMTYwYjUxZTUyYzBlOTY3OWRhNjcwMTk4NSJ9fX0="
|
||||
),
|
||||
"Plains Fletcher Villager", "villager.plains.fletcher", "85a158e9-23a3-495c-a7cf-0bb4b924bfaf",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODIxNTg4ODRlYzQ1YzI2YjA2ZTA0YWM4MDM1NWJjYjViNzYwYjQ2MDkzOTYzODljOTQ4MzA1ZjAzYjNkYWU5ZCJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_PLAINS(//
|
||||
"Plains Leatherworker Villager", "villager.plains.leatherworker", "641edbf6-0351-4eb8-a0f2-2ad61bfc93dc",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWQ0NDY4YjMzYzE2Mzc1OGUzYmM3Yzk2OTRjODA0YmZmNGY4YTVmMTYwYjUxZTUyYzBlOTY3OWRhNjcwMTk4NSJ9fX0="
|
||||
),
|
||||
VILLAGER_LIBRARIAN_PLAINS(//
|
||||
"Plains Librarian Villager", "villager.plains.librarian",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTgxODYyNDEsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjBmMjQ3YjU3MDI0NmMyYWYzOTRhZDA0MGM4YWYzZjYwNWY4ZWI2YTNiYjg2OTExY2QyNDkyNDM4MjU2ZWFhOSJ9fX0="
|
||||
),
|
||||
"Plains Librarian Villager", "villager.plains.librarian", "4df8080c-dcb8-4aee-8c1e-3e8d02aa6c4d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjBmMjQ3YjU3MDI0NmMyYWYzOTRhZDA0MGM4YWYzZjYwNWY4ZWI2YTNiYjg2OTExY2QyNDkyNDM4MjU2ZWFhOSJ9fX0="
|
||||
),
|
||||
VILLAGER_MASON_PLAINS(
|
||||
"Plains Mason Villager", "villager.plains.mason",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWUwZTk1OTFlMTFhYWVmNGMyYzUxZDlhYzY5NTE0ZTM0MDQ4NWRlZmNjMmMxMmMzOGNkMTIzODZjMmVjNmI3OCJ9fX0="
|
||||
),
|
||||
"Plains Mason Villager", "villager.plains.mason", "08d93422-d0e1-4020-a38f-b38995e05e6f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWUwZTk1OTFlMTFhYWVmNGMyYzUxZDlhYzY5NTE0ZTM0MDQ4NWRlZmNjMmMxMmMzOGNkMTIzODZjMmVjNmI3OCJ9fX0="
|
||||
),
|
||||
VILLAGER_NITWIT_PLAINS(//
|
||||
"Plains Nitwit Villager", "villager.plains.nitwit",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTkxODUxMTIsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTM0NWEwY2FkZDAyZmI3NTYwNjZlMDNjNDBjYzFhYjVmZTlhZDRhZjQ5NmU4OGYyYmJhMTBmNWUxNDZmMDkyNSJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_PLAINS(//
|
||||
"Plains Villager", "villager.plains.none",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTk2MTMwOTgsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWEwZTNkNDFlNmViZTUzOWUwZWI0OGE2N2YyZWM1ZGEyMjRkNDA4Yjk5Y2VkOTI0ZjlkMGE4MTVlMzVjNTdhMiJ9fX0="
|
||||
),
|
||||
"Plains Nitwit Villager", "villager.plains.nitwit", "ee0b1913-5636-4358-86bd-fcf48ea59462",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTM0NWEwY2FkZDAyZmI3NTYwNjZlMDNjNDBjYzFhYjVmZTlhZDRhZjQ5NmU4OGYyYmJhMTBmNWUxNDZmMDkyNSJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_PLAINS(//
|
||||
"Plains Villager", "villager.plains.none", "58404a7e-a14d-4b48-b97c-cdb98a8e1018",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWEwZTNkNDFlNmViZTUzOWUwZWI0OGE2N2YyZWM1ZGEyMjRkNDA4Yjk5Y2VkOTI0ZjlkMGE4MTVlMzVjNTdhMiJ9fX0="
|
||||
),
|
||||
VILLAGER_SHEPHERD_PLAINS(//
|
||||
"Plains Shepherd Villager", "villager.plains.sheperd",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDA1NDAzMTUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmVkNmI1ZTFlOWNiNDUxYzEyMWUyZWMwZmExYjU5MDc3OThlOWZkM2E1ZWE2ZDAwY2NmYWYxZDdlMmMxMDc5ZCJ9fX0="
|
||||
),
|
||||
"Plains Shepherd Villager", "villager.plains.sheperd", "1e93dceb-d8d8-45c4-88e8-890a54e80b40",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmVkNmI1ZTFlOWNiNDUxYzEyMWUyZWMwZmExYjU5MDc3OThlOWZkM2E1ZWE2ZDAwY2NmYWYxZDdlMmMxMDc5ZCJ9fX0="
|
||||
),
|
||||
VILLAGER_TOOLSMITH_PLAINS(//
|
||||
"Plains Toolsmith Villager", "villager.plains.toolsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDA5ODQyMDcsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzU5YjYzMmEwOTI1MTZkOTYzMzk4MDY5YjFhZTI4YzFjZGJiY2NjMThkNjcyMDAzM2M2M2YzODhkODc5YzRhIn19fQ=="
|
||||
),
|
||||
"Plains Toolsmith Villager", "villager.plains.toolsmith", "75cf97b1-4d89-4ac8-94e1-f85fac14871a",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzU5YjYzMmEwOTI1MTZkOTYzMzk4MDY5YjFhZTI4YzFjZGJiY2NjMThkNjcyMDAzM2M2M2YzODhkODc5YzRhIn19fQ=="
|
||||
),
|
||||
VILLAGER_WEAPONSMITH_PLAINS(
|
||||
"Plains Weaponsmith Villager", "villager.plains.weaponsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDE0ODQ1MzksInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWIxZWE1NGI3ZmQ5M2ZlNmMzNmQwYjVkODE1YWIwZGI4OWRiODk0ZGI3NWNlMGZjZTczOGU5NGVlOGI3OWUxOSJ9fX0="
|
||||
),
|
||||
|
||||
VILLAGER_ARMORER_DESERT(//
|
||||
"Desert Armorer Villager", "villager.desert.armorer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDAwNTA5MDcsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWI2N2EwZmI1MGYyOGM2ODhiZTk3ZDEyN2NmZTQwNTQ3ZDE4N2U4MjliZDI5MTUwMjA1MzNjZmU5M2JhMDRhIn19fQ=="
|
||||
),
|
||||
VILLAGER_BUTCHER_DESERT(//
|
||||
"Desert Butcher Villager", "villager.desert.butcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDEyOTIzNDQsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDc3NjZhZWJlYzJlZGU4ZTg2MGU0YjMwYmNlZWIyYTM0NTU4MTYzMzM5MDkwZWZiMzhhNDY1MDBmYjUwOTMyYyJ9fX0="
|
||||
),
|
||||
VILLAGER_CARTOGRAPHER_DESERT(//
|
||||
"Desert Cartographer Villager", "villager.desert.cartographer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDIwNzc2NTUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmY5NDY3Y2QzNTc0ZTNiNjUwNDJiZjIxZjM2OWRhNjBmNzc3ODMyNzVkNDkzMGQzZTBkODI2MWI4YjUyOTc3MyJ9fX0="
|
||||
),
|
||||
VILLAGER_CLERIC_DESERT(//
|
||||
"Desert Cleric Villager", "villager.desert.cleric",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDI3MDEwODEsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTE0NWViMDM5ODljMTA0MDFhYzdhM2U0ZWE4MTY1MmFjM2MxZDg4NTM3NTA4NThiY2ZiZDhmOTQyYmU5NTI5ZiJ9fX0="
|
||||
),
|
||||
VILLAGER_FARMER_DESERT(//
|
||||
"Desert Farmer Villager", "villager.desert.farmer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDM0MjgyMTksInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODZmYjM4OGY3MGNkMjQ5Yzk4YWQ2MTcwZThjOWIzNzU3NjY3MWQ3NzFjZDhmNzJkOWYxNzMwYjhjOWNhMjMyNSJ9fX0="
|
||||
),
|
||||
VILLAGER_FISHERMAN_DESERT(//
|
||||
"Desert Fisherman Villager", "villager.desert.fisherman",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDQwNTc1NTAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmQ1NDk1NDNhMTg2NTc5NGE4N2YwMDI1YjZmOWJiZWU3ZmM3OGNiYmI0ZThhZWVmYTFjMzdmODU3MzRlNDAxOCJ9fX0="
|
||||
),
|
||||
VILLAGER_FLETCHER_DESERT(//
|
||||
"Desert Fletcher Villager", "villager.desert.fletcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDUwMTYyMjUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGJiMjBmMjljY2NlZWEwNzA3M2I4NDY4NGIzOTA5NjMwZGQxMTVhNDdkMmZlYzdjM2QyZjhiY2I5OTkyZTEwZCJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_DESERT(
|
||||
"Desert Leatherworker Villager", "villager.desert.leatherworker",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzMDkxOTk0MTIsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODgzZTliYzgyN2U3MzFhYTFkODAxNDg3ZTViNmEzOTE2YWQ0NTJkZGMyMDY4ZmFiMDdlOTdlYmM5MDM2ZTA1MiJ9fX0="
|
||||
),
|
||||
VILLAGER_LIBRARIAN_DESERT(//
|
||||
"Desert Librarian Villager", "villager.desert.librarian",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTg0Mjc4ODAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjljMzA4M2JkMjQ5MGVlNDExZTAyZTE1MDliZDRmYzhiZjU0ZjkwZTkzMmI0YzU0NGE1YzEwNzg4MzA1NzhhYyJ9fX0="
|
||||
),
|
||||
VILLAGER_MASON_DESERT(
|
||||
"Desert Mason Villager", "villager.desert.mason",
|
||||
"eyJ0aW1lc3RhbXAiOjE1Nzc2MDk0NTI1NDQsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGRkODUxNTJlMzk5ZDMwMGM4NmRkYjRkZWUxNDIzNGJmODM2M2ZiYTE3NjQyZGI0MjE5ZTM3ODJhZjE5OGM4ZCJ9fX0="
|
||||
),
|
||||
VILLAGER_NITWIT_DESERT(//
|
||||
"Desert Nitwit Villager", "villager.desert.nitwit",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTkyNjgwMjMsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjNkZDYxZjQxODRkY2Q0Y2YxMDBiNjAyMTQxZDNjMmJiNmMyMjIxN2E3ZWQ4MjZhNzgxNWI1ODdkZWNhNTBiNyJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_DESERT(//
|
||||
"Desert Villager", "villager.desert.none",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTk2Nzc0MjMsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTMzOTM1MjdhZmE2ZjcyYmQxYjJkNTliOTU3Yzc0MDk1ZWViNDNjZjkzNzg0ZTAxZmM2NjdmMzkyNmFhNzU5ZSJ9fX0="
|
||||
),
|
||||
VILLAGER_SHEPHERD_DESERT(//
|
||||
"Desert Sheperd Villager", "villager.desert.sheperd",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDA2MDI2MzIsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzM5ZTEwNzVmNjhiZDVhYmM1ZWY5NjllMzA4NTZjODU5MjgzNTc4MGYwM2FhZjViMmY1OTYyMTZmYWIwMDI2YiJ9fX0="
|
||||
),
|
||||
VILLAGER_TOOLSMITH_DESERT(//
|
||||
"Desert Toolsmith Villager", "villager.desert.toolsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDEwNjkzMzMsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTE0ZGJmNDYzMGQ0YTFmMTA5ZWE3YWYwZDAyNDc4OGVmMTQyNWJkYjg5OWMxYWUxNDA4Y2UzZjlmZTRiMmRmMyJ9fX0="
|
||||
),
|
||||
VILLAGER_WEAPONSMITH_DESERT(
|
||||
"Desert Weaponsmith Villager", "villager.desert.weaponsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDE1ODIzOTEsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjFiZDhlYjMwMDkzYzkxZDA2NzVmNzMyMWY5NWFkOTFkNjk1ZjRhMmNjNmIxZTk2MzcyOTk4ZGUyNGQ2NmI2OSJ9fX0="
|
||||
),
|
||||
|
||||
VILLAGER_ARMORER_JUNGLE(//
|
||||
"Jungle Armorer Villager", "villager.jungle.armorer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDA2NDkyNDAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjFkNTk5ODM1OTQ0NDc2ODk4MzAxODI2MDkyNjU3OTJlZGYxZTM1ZTlkMzYyYWQ2MmRiOWNmNzY5ZWE3MTVhMiJ9fX0="
|
||||
),
|
||||
VILLAGER_BUTCHER_JUNGLE(//
|
||||
"Jungle Butcher Villager", "villager.jungle.butcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDEzNDc2MTYsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2EwNTE1MDYwMjM3ZDVhZmFhNGI3NmY3ZWQyOTgwYzdmMDUzZjcwNTAzYTlhNjg5Y2M2ZjE0NmFiZGM3ZDk4MCJ9fX0="
|
||||
),
|
||||
VILLAGER_CARTOGRAPHER_JUNGLE(//
|
||||
"Jungle Cartographer Villager", "villager.jungle.cartographer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDIxNjAwMjUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2I0YjA5MTYwOTZhNjBkM2UzODVhNGZmOTc4Njg2OWU3ZDNlZGE1MjM4MzUxYzM5OThjZmI2ZDcwYzY2MWVhIn19fQ=="
|
||||
),
|
||||
VILLAGER_CLERIC_JUNGLE(//
|
||||
"Jungle Cleric Villager", "villager.jungle.cleric",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDI3NzkwNTksInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGEwZWYyYWRkMThhNDU3ZGY4YTk4ZWM1OTFiMGEwZGJkOTk0MmEyZDU4OTY1YTA0M2VhMDM5NzIwNDg3MTRmNSJ9fX0="
|
||||
),
|
||||
VILLAGER_FARMER_JUNGLE(//
|
||||
"Jungle Farmer Villager", "villager.jungle.farmer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDM0OTY0MjAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTQ5YmZjZTFkZTRkOWU3OGE3YTk2ODc3MzE5ZWRhOTBlOTg5YzI4YWZlMWI0YmYxZGM1NjNhNWQ0NGIxYWM3NCJ9fX0="
|
||||
),
|
||||
VILLAGER_FISHERMAN_JUNGLE(//
|
||||
"Jungle Fisherman Villager", "villager.jungle.fisherman",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDQxMTI0MzcsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmU0M2MwYmYyNmVlMWE0MzMyYzExZTJjMjA4N2FhZDkwM2JlNDE4YWNhNTE0ZmQ4MGE3MDI4YjM3MWY1MzI4NyJ9fX0="
|
||||
),
|
||||
VILLAGER_FLETCHER_JUNGLE(//
|
||||
"Jungle Fletcher Villager", "villager.jungle.fletcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDUwNzY5MjcsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjg0MjM4ZjA2YTg1YWM2NzY1MWQ5NmNmOTYzYzUyNTA1NTI5OTI5MGMzNDg4MjlhNjZjNDQ1OTdiYWY1NzQwYiJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_JUNGLE(
|
||||
"Jungle Leatherworker Villager", "villager.jungle.leatherworker",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzMDg3NTk3OTIsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWEwOTU1ODdhYWZlMThjNWZlZTBiYWExNzk1ZmMyMjk0OGYyZGRjZGMzMmEzMzUwMzIzZDMzZGI1OTE4MDBlNiJ9fX0="
|
||||
),
|
||||
VILLAGER_LIBRARIAN_JUNGLE(//
|
||||
"Jungle Librarian Villager", "villager.jungle.librarian",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTg0OTY3NTMsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTJmYzNkMGU3Yjc0ZGY1N2NiNGJkNmM0MjZhYTM2MWY3NjIwMjk2ODUzMGU3NmNmZjU5YjM5MzQ3MTc5NTk4YiJ9fX0="
|
||||
),
|
||||
VILLAGER_MASON_JUNGLE(
|
||||
"Jungle Mason Villager", "villager.jungle.mason",
|
||||
"eyJ0aW1lc3RhbXAiOjE1Nzc2Njk1NTU2MjksInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTk2NzU2ZWU5MDNkMThkNTFhNWQ5NTk2M2I4NWJiYzEyYmI3YmQzOTEzZTg4NzE3ZDA2ZjhmOGU5YzU0MDFhYyJ9fX0="
|
||||
),
|
||||
VILLAGER_NITWIT_JUNGLE(//
|
||||
"Jungle Nitwit Villager", "villager.jungle.nitwit",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTkzMjg3MjQsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzFhZWY1MTNkYjdhYzJhZjViNmI4YzliOGUyYjlmNDYyMjgxNGQxNTFlNzUwNGQ5YWUyYzQ1ZjRkOTRlOTBhNiJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_JUNGLE(//
|
||||
"Jungle Villager", "villager.jungle.none",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTk3Mjk3NzAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTgwNmU5YTRkNzI4ZTcxNjgwM2ZjN2M3N2MxNTg2YzBkNWVkODViODZmNDA4MGI1YmRiNjQwY2M0N2YxNWI3ZCJ9fX0="
|
||||
),
|
||||
VILLAGER_SHEPHERD_JUNGLE(//
|
||||
"Jungle Sheperd Villager", "villager.jungle.sheperd",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDA2NTAxNjYsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTk3NzY0MzBjZDIwYTY5YTFkODk5ZDlkMWRjZDMxZDdkMTM0MmI1NWU4MDE1YjdmMDYwZmIzYTJjMzM4YzhiYyJ9fX0="
|
||||
),
|
||||
VILLAGER_TOOLSMITH_JUNGLE(//
|
||||
"Jungle Toolsmith Villager", "villager.jungle.toolsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDExMTk4MjUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjg2MzVmOTFhYjhlOTU0MmQwNTAyODRmMDhkMGRjYTVkZjZjMWYzYmQ2ZDhhNzE0MjdkMTQxOWUzNzk5YzJiYyJ9fX0="
|
||||
),
|
||||
VILLAGER_WEAPONSMITH_JUNGLE(
|
||||
"Jungle Weaponsmith Villager", "villager.jungle.weaponsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDE2Mjg2ODgsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjQ1ZmFiMzAzMjk0NGQxOGIyNjYyMWFkMjliM2Y5M2M0OTI3NmVkNmViNDY5ZWUyMTNhYmVjOGU0MmIyMjZhMiJ9fX0="
|
||||
),
|
||||
|
||||
VILLAGER_ARMORER_SAVANNA(//
|
||||
"Savanna Armorer Villager", "villager.savanna.armorer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDA4NDU1MDAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmU4YTBlZGQwODFmZTE3NjFhZDU0YzY3ODNjOWZjZDJkZjA2M2YzYzIyODc0MjBmYzZkMjkzOWRmY2Q3MDI0OSJ9fX0="
|
||||
),
|
||||
VILLAGER_BUTCHER_SAVANNA(//
|
||||
"Savanna Butcher Villager", "villager.savanna.butcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDE1MzkwNzEsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTUxZTAwMzkxZjcxNGI1NTk5ZmQ4NTQ4NWE3NGZkM2MxOTkwY2VmMWJkMjgyMTBjZThmNTk2NjE4MDA4ZDVjYiJ9fX0="
|
||||
),
|
||||
VILLAGER_CARTOGRAPHER_SAVANNA(//
|
||||
"Savanna Cartographer Villager", "villager.savanna.cartographer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDIyMzIwMzAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjAxZWEzNzc2M2M4OTU5MzY3ZTNjM2FmOTM4YjU3YzU2NjI2OTMxMmM4YjBlY2VmMWY5ZjY0ZmQ4ZmE4YTkxOCJ9fX0="
|
||||
),
|
||||
VILLAGER_CLERIC_SAVANNA(//
|
||||
"Savanna Cleric Villager", "villager.savanna.cleric",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDI4NDYxMjAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWIyY2JmZjE0ZjZiYTdmYjFjMjdkM2ZiZDYyOGI2MjM0NzUyNTMyMmJhMGY4ZWU5Y2EwZWIzNDkzYjg4Yjc2NCJ9fX0="
|
||||
),
|
||||
VILLAGER_FARMER_SAVANNA(//
|
||||
"Savanna Farmer Villager", "villager.savanna.farmer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDM1NTU5MTgsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzc0OGM3Yjk5MGFkMjMzNWFjNTU5MWQ4ZWNiYzYxZGRjNjdhMzU4YTcwN2VkMWIyNmUyYmFmMjM5YTcwZGEwOSJ9fX0="
|
||||
),
|
||||
VILLAGER_FISHERMAN_SAVANNA(//
|
||||
"Savanna Fisherman Villager", "villager.savanna.fisherman",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDQxODg4MzcsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTkzZDQ5NzljMDU0NGI2ZGQxNjNhMjBjODZlM2E0NjZhN2ExMDI4NDA5M2QwZGMzMTNlOWY3ZGUyMGZlZTRlZiJ9fX0="
|
||||
),
|
||||
VILLAGER_FLETCHER_SAVANNA(//
|
||||
"Savanna Fletcher Villager", "villager.savanna.fletcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDUyMzEyOTksInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzAyODEyZmU3ZTA3NTI0MTEyMDkxYTI5ZTBiOTE1MmNkMmEyZmJmOTRhYTlhN2EyMTkzYzRkOGE3M2RjNzNmMSJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_SAVANNA(
|
||||
"Savanna Leatherworker Villager", "villager.savanna.leatherworker",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzMDgxNDk5ODQsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjVhN2U2YThlZGVlZjc0ZGM1ODQzOGQ3MDZmYjJhZWQ4ZWNiZWI0ZjlhNGQ5NTY2MGY1ZmY1MDZlNGFmM2Q1In19fQ=="
|
||||
),
|
||||
VILLAGER_LIBRARIAN_SAVANNA(//
|
||||
"Savanna Librarian Villager", "villager.savanna.librarian",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTg1NjE5MzUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTNjNTQ3NmJmYTMxYWY4YTQ2NDliNjc5NzY1MjhiMzAxZmY5YjhiYTU3NWE4YzgxYzlmMDlmMzhiNjkyNzgxZSJ9fX0="
|
||||
),
|
||||
VILLAGER_MASON_SAVANNA(
|
||||
"Savanna Mason Villager", "villager.savanna.mason",
|
||||
"eyJ0aW1lc3RhbXAiOjE1Nzc2NzEwMzEzMTUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQwNWZkMTNkNGU3ODYwNzUxMmZmNzE2OWYzZWQ1NmIzMTA0MjM5M2QzMDlhYzhlODIzNjZlMTE3OGJiYTVjMiJ9fX0="
|
||||
),
|
||||
VILLAGER_NITWIT_SAVANNA(//
|
||||
"Savanna Nitwit Villager", "villager.savanna.nitwit",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTkzODQyOTksInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjE0N2MzMTVlMzg1ZmRlMWFmZjI5MmMwNGEzNzM5MGE2ODNlZGQ0NTYxMGU1OThmOTBjOWExYThhNTY3YjJmNSJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_SAVANNA(//
|
||||
"Savanna Villager", "villager.savanna.none",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTk3Nzc0ODMsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTQ3MGIyNTE2ODhiYTU4MDc3NDIwOWQ1MjY2NDAwMmYzMDk3MzRkYzljOWMyMTZmMGQ3MTY3ZjNkYmRhZGVjMCJ9fX0="
|
||||
),
|
||||
VILLAGER_SHEPHERD_SAVANNA(//
|
||||
"Savanna Sheperd Villager", "villager.savanna.sheperd",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDA3MDA2MTgsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDczMTgxYzA0NzNiN2IxMTExYTVkYmFiMmQyNDQzNzI5ZTdiZmQ4NDk5YjEyZmZlODdhYWYxZTExM2IyYWEyOSJ9fX0="
|
||||
),
|
||||
VILLAGER_TOOLSMITH_SAVANNA(//
|
||||
"Savanna Toolsmith Villager", "villager.savanna.toolsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDExNjY5MzQsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGQ4YzBlZjEzMGZiNWIxZDcxNjlhY2M4NThhOGU3ZGNlMzM2NjI5YWNmN2JmODhkMzE2MmNiNDA5YjQ5NzE0MCJ9fX0="
|
||||
),
|
||||
VILLAGER_WEAPONSMITH_SAVANNA(
|
||||
"Savanna Weaponsmith Villager", "villager.savanna.weaponsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDE2ODk4NjIsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzc0MmE0ZGJiYjgwZWRhZDk2MmM3NThmYjc0NmEyMzYzOTYzODdhMDIzNzA2NDVhYWZjOGM0NDJjOThlMjk3ZiJ9fX0="
|
||||
),
|
||||
|
||||
VILLAGER_ARMORER_SNOW(//
|
||||
"Snow Armorer Villager", "villager.snow.armorer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDA5MTAyNDUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmEwODUxMGI1ZjYwNjlkOTQ4OGFkY2FmMDc4OTViM2U3OWEzMTViMTlhYWYwMTM5NTQ5NDkyMmE2ZjlkYTdhZiJ9fX0="
|
||||
),
|
||||
VILLAGER_BUTCHER_SNOW(//
|
||||
"Snow Butcher Villager", "villager.snow.butcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDE1OTUzNzgsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzMwMjJjMzY4MGEyNDAyMTA1YTc5MjIxNDM2OTU0ZmNmYWQwZDNjN2E3YWZjOTg4MmQyOTMxMDM1ZTA3NzI4NyJ9fX0="
|
||||
),
|
||||
VILLAGER_CARTOGRAPHER_SNOW(//
|
||||
"Snow Cartographer Villager", "villager.snow.cartographer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDIzMDUwMzcsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2JkNDM5NjZmYjNmN2M3NDA2OGNmYjRjOGM4OWU4NjJhNWNkZWMzNDk5NWMxMjI4NTk2NzVlOGQ5ZjlmNGMwZiJ9fX0="
|
||||
),
|
||||
VILLAGER_CLERIC_SNOW(//
|
||||
"Snow Cleric Villager", "villager.snow.cleric",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDI4OTYwOTYsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWUwMjNkMWE5ZGVhODM0OGIxM2Y0YzFlZDI2YmM3MWNlZWQ1N2VkYmEwNTZjYjc3NTI4ODc1YzUwNDMxYmFmYSJ9fX0="
|
||||
),
|
||||
VILLAGER_FARMER_SNOW(//
|
||||
"Snow Farmer Villager", "villager.snow.farmer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDM2MDE0NTksInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2M0OTEyYmNiOTY0NmQ5MjkyYzZhNzIwZTU0Nzc1NDE2MTVlNDg0MjQxZTE3NDU0NzcwY2I0ZGRhMzBlM2FlMyJ9fX0="
|
||||
),
|
||||
VILLAGER_FISHERMAN_SNOW(//
|
||||
"Snow Fisherman Villager", "villager.snow.fisherman",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDQzNjY5MjQsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTBmMWVjNzEwZmFhMzhiYWUzZTc5NTE5NjEzODkyNTQ1ZjM0ZTRlZDM4N2ZhZGEyZDdkODA0YmM5ZDg0NjUwMiJ9fX0="
|
||||
),
|
||||
VILLAGER_FLETCHER_SNOW(//
|
||||
"Snow Fletcher Villager", "villager.snow.fletcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDUzNTY2MjksInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzY1NDcwYTM1NzU1ZTU1OGI2MzNmZDM0ZTEwOGFhNTYyMDJhYjNlZDU5NmNmNGYxOTQ3ZTk3YTEzMmU1MDNjNyJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_SNOW(
|
||||
"Snow Leatherworker Villager", "villager.snow.leatherworker",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQyNTgyNTUwNDQsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDM1MjMwNDFhMjE2M2Y3MTY5NDFjZGE3MjcxMzhiOTgxMzdhZTRmNzU3ZjNlNzFlOGIwYzFiMmEyOGQ3ZTZiYSJ9fX0="
|
||||
),
|
||||
VILLAGER_LIBRARIAN_SNOW(//
|
||||
"Snow Librarian Villager", "villager.snow.librarian",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTg3MTI2NTQsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWI5NmIwNmM3ODZhOTAwNjI4MTgwNDVjYzZlMTNmNWI3MTA0NjQ5MTg0MDFiYzVhMjExODZiOWZjNGM4NGYzYiJ9fX0="
|
||||
),
|
||||
VILLAGER_MASON_SNOW(
|
||||
"Snow Mason Villager", "villager.snow.mason",
|
||||
"eyJ0aW1lc3RhbXAiOjE1Nzc2NzIzNTE2OTUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGUyYThlNjRmYzBlYjIxZDNlMjNkMWQxZGU0ZThiODA2MmQ3NGI4NjY3NTliYzk2OGYxMzA5NmRmYWUzYzM4YiJ9fX0="
|
||||
),
|
||||
VILLAGER_NITWIT_SNOW(//
|
||||
"Snow Nitwit Villager", "villager.snow.nitwit",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTk0NDQyOTgsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzRhYTk1ODc3NDAxNWQ3N2UwM2Q5Mjg1ZDcxYTI4NzY5NDUxNWU3N2RjZmYzYjAwNjBlYjg1NjU4YWZmYzU3NiJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_SNOW(//
|
||||
"Snow Villager", "villager.snow.none",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTk5OTc3MzgsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzRiYWNjOTBlYTFjNGQ4ZjBiOGQ4YjkzMTY1NWY0ZWM0OTFkYmY1OGYwNTIzNzJmNDQ5MDkyZWY1YTkxNDIzNyJ9fX0="
|
||||
),
|
||||
VILLAGER_SHEPHERD_SNOW(//
|
||||
"Snow Sheperd Villager", "villager.snow.sheperd",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDA3Njk2MjAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2U5YzI5YTJhYjkxOWE5N2Y4NGEwYjVlMGFkYjA0NTEzZWJlZmExNzRjM2IwZDcyNWI4NGNlNDgyNjkzZjdjZCJ9fX0="
|
||||
),
|
||||
VILLAGER_TOOLSMITH_SNOW(//
|
||||
"Snow Toolsmith Villager", "villager.snow.toolsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDEyMTQzMzUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmEzZTA5MjI2ZWNkNTM2ZDZjNThiNTQ5NzkwZTFmYTdlOTMyNjAyOGE3MDM3MDUyOTIxYTAwNDI2Y2FmMTBlYSJ9fX0="
|
||||
),
|
||||
VILLAGER_WEAPONSMITH_SNOW(
|
||||
"Snow Weaponsmith Villager", "villager.snow.weaponsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDE3MzM5NzUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDkyNjZhZGZjYWRiYjBiODY5YjEwZTIyNjQwOWMwODNjNmRjN2EwNzE5YTZjODA4Y2JjMjM2NzY1YWI4YzBlZSJ9fX0="
|
||||
),
|
||||
|
||||
VILLAGER_ARMORER_SWAMP(//
|
||||
"Swamp Armorer Villager", "villager.swamp.armorer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDA5Njc0ODAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzE4NDBlNDA4MmY0YWVhYTY5NTM1NDg0YTdhYjdkOGY3ZTEzYzVjNTc4OWEyYTM4M2JkN2U4N2IzODc5MDZjNSJ9fX0="
|
||||
),
|
||||
VILLAGER_BUTCHER_SWAMP(//
|
||||
"Swamp Butcher Villager", "villager.swamp.butcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDE2NTM2NzQsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjUyNmZhYTQ2NmRkMzcxNjhhYWMxYzYwY2JjN2U1YTI0MDVjOTM1MDcxZGVhNmNjMWUzYjllYWJmODdlYmExYyJ9fX0="
|
||||
),
|
||||
VILLAGER_CARTOGRAPHER_SWAMP(//
|
||||
"Swamp Cartographer Villager", "villager.swamp.cartographer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDIzNjUyMDcsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDIwNWVkM2Q4MmRjNTI1MDExZWMzOTIwODA5MTY1MDVmZjg2Y2E5NjE3YWQwZjJjNzI5NmI5OTA3ZmEyZmI4YiJ9fX0="
|
||||
),
|
||||
VILLAGER_CLERIC_SWAMP(//
|
||||
"Swamp Cleric Villager", "villager.swamp.cleric",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDI5OTg3OTMsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGM0Mjk2NDg2Y2NlYzgxYWNkZjIxNDUxYzY5MGIyMzRiYzlmZGFjNWFiNmVmZDU0NTFhYjVjZGFmYWZiNzk3OSJ9fX0="
|
||||
),
|
||||
VILLAGER_FARMER_SWAMP(//
|
||||
"Swamp Farmer Villager", "villager.swamp.farmer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDM2NDY4MDEsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzQ4ZDVmODA4NDc4NTRlOGNkNTU2ZjE4NDdjZTM3M2E5OGJiYzdkZDAyMzJiNmUyMDY0NzQyNDQxMTk2NDg5NiJ9fX0="
|
||||
),
|
||||
VILLAGER_FISHERMAN_SWAMP(//
|
||||
"Swamp Fisherman Villager", "villager.swamp.fisherman",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDQ0MzA4OTcsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODMyZTk4ZmM1ZDc3OGE0ZTM0ZDU1OTc2MWQ1YWY0YTYzYjJlMTZlZDkxZmE3N2E1NDJhZDdmNDlmZjA0MTM1MCJ9fX0="
|
||||
),
|
||||
VILLAGER_FLETCHER_SWAMP(//
|
||||
"Swamp Fletcher Villager", "villager.swamp.fletcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDU0MzgwNTcsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmQ0ODQ0ZmUyZmI4N2QxNzEzMDY5MjU2MjRkYmM5ZjVjZGNmOGYyYTJjYjlkYjI1ZTJiNzdhMjc3OTAyYmFhZCJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_SWAMP(
|
||||
"Swamp Leatherworker Villager", "villager.swamp.leatherworker",
|
||||
"eyJ0aW1lc3RhbXAiOjE1Nzc2NzMzMTcyMTEsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTMzNGQ3OWY4ZmI0MjAzZDRiZmFhYWM4ZDU5NTVmZTA5NjVkY2JiMDMzNmVmMTY3NTc1NjdlMWQwODQyYjhhMyJ9fX0="
|
||||
),
|
||||
VILLAGER_LIBRARIAN_SWAMP(//
|
||||
"Swamp Librarian Villager", "villager.swamp.librarian",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTg3NjQzMDYsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDI0MzU3ZWVkMGEzYTM5NGEyNmJkZjhmYzhlNjEzZTgzNjE5NmE3MmE1OTRkNWUwYWFiNmYzMDcyM2NjNDRkNCJ9fX0="
|
||||
),
|
||||
VILLAGER_MASON_SWAMP(
|
||||
"Swamp Mason Villager", "villager.swamp.mason",
|
||||
"eyJ0aW1lc3RhbXAiOjE1Nzc2NzMzMTcyMTEsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTMzNGQ3OWY4ZmI0MjAzZDRiZmFhYWM4ZDU5NTVmZTA5NjVkY2JiMDMzNmVmMTY3NTc1NjdlMWQwODQyYjhhMyJ9fX0="
|
||||
),
|
||||
VILLAGER_NITWIT_SWAMP(//
|
||||
"Swamp Nitwit Villager", "villager.swamp.nitwit",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTk1MDM4MzQsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzNmMGE2ZmRkNTkxNmRlNjhmN2Q5ZGM5ZmY5ZGQ5YWFkNWM3ZjNmMWQyYmJmNzJiOTU2YWQ0NTMzZTJkNmU1ZSJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_SWAMP(//
|
||||
"Swamp Villager", "villager.swamp.none",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDAwNTIyMTksInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTU1MWE0OTlmN2FiMTc3YmE0M2FjYTQxZGZkOGZjNDExYjFkMWU1MDJhMzQ2ZjljNGQ2MGI3YTVlNTdmNDM2YyJ9fX0="
|
||||
),
|
||||
VILLAGER_SHEPHERD_SWAMP(//
|
||||
"Swamp Sheperd Villager", "villager.swamp.sheperd",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDA4Mzg4ODAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDU0NWM0MWY3NGU1OThiYjE0ZDRlMTUyNGRhMzg1ZDU0YTRhZjYxMDA5YmM5MGRlYTA3MGZhY2NjZjMwYzViMiJ9fX0="
|
||||
),
|
||||
VILLAGER_TOOLSMITH_SWAMP(//
|
||||
"Swamp Toolsmith Villager", "villager.swamp.toolsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDEyNTc2MzksInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmM0YjE4Mzk4MWU0ODUxNDYxZTdiYjljNzEwY2Y4ZTViNjU3NWZiMjI0YzJhYzBjNmU1Y2FkM2MyYTVkMmY5OSJ9fX0="
|
||||
),
|
||||
VILLAGER_WEAPONSMITH_SWAMP(
|
||||
"Swamp Weaponsmith Villager", "villager.swamp.weaponsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDE4MTIzNzgsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTUwZjUxNzkxNjBmYTM1NDU0NzUyOTM1MDI2YmViY2Q5ODc1MTk5Njc1MGY1NGVjNWY5NTNhY2I4N2NiZWJjOSJ9fX0="
|
||||
),
|
||||
|
||||
VILLAGER_ARMORER_TAIGA(//
|
||||
"Taiga Armorer Villager", "villager.taiga.armorer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDEwMzA1MjIsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2YxYmE0MTQ1NGZjNTVkZGUwNzlmYzE1YmYyMTQ2MTg5MWQ1YjVkMDNkZDQwMTZhZTdjZGViNDZhOGZjODQwNCJ9fX0="
|
||||
),
|
||||
VILLAGER_BUTCHER_TAIGA(//
|
||||
"Taiga Butcher Villager", "villager.taiga.butcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDE3MDE5MTQsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjI4ODdhMGZmNzg5YTdmY2FiOGU3NzhlNzEwZGJhZDBkOTYxZWJiYWFmYTVlZTA0MGUyMTM1YzVkM2E4Y2M3MiJ9fX0="
|
||||
),
|
||||
VILLAGER_CARTOGRAPHER_TAIGA(//
|
||||
"Taiga Cartographer Villager", "villager.taiga.cartographer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDI0Mjk5NDEsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzA4OWZiMjQ2YWEyZjNlZjI3NGQwMTQyOWQzNTM0NzE5ZTQyYjFhODE1MWNkYWMzMDM1NGQ0OTY3YjczYTc4MCJ9fX0="
|
||||
),
|
||||
VILLAGER_CLERIC_TAIGA(//
|
||||
"Taiga Cleric Villager", "villager.taiga.cleric",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDMwOTUwNDgsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2M1ZGVhOTljMjg2NzE4NTczOGJlMDJiNzFjYWNmMmNkYTRhMjczYzExNDliZTdhNTE2NGRhNzJmMGY5NDZmNyJ9fX0="
|
||||
),
|
||||
VILLAGER_FARMER_TAIGA(//
|
||||
"Taiga Farmer Villager", "villager.taiga.farmer",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDM2OTI4ODcsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTU3ZjM4M2IwYmRiNDU2OTU3Y2ZiY2M1MmIyODA4YTBmOGEwMGMzNTlkMTVhZWIwMTNmNTYzNGZhMDAzNzkyIn19fQ=="
|
||||
),
|
||||
VILLAGER_FISHERMAN_TAIGA(//
|
||||
"Taiga Fisherman Villager", "villager.taiga.fisherman",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDQ1MTkyMjUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWI5YzZlZGI1YzBiYTU0YjIwM2RiZjA0ODI3M2M0YmFkYjE1Y2VjMWQzMjI4NjUwZDJjMmZlNWIzZmFiM2NiYiJ9fX0="
|
||||
),
|
||||
VILLAGER_FLETCHER_TAIGA(//
|
||||
"Taiga Fletcher Villager", "villager.taiga.fletcher",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzNDU0OTE1MDYsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDllMTVmODQ4YjUwODMyMGRiZjE2NGJmMGQ0YmFjODlkNTE3MWYxODZiZWViNDFjN2JkMzQ2MDExYzg3YmQ4YiJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_TAIGA(
|
||||
"Taiga Leatherworker Villager", "villager.taiga.leatherworker",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQyNTY5MDM3MzYsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2VhNTI0ZjM3ZjYyYmI1YWQyMWYyZmEzNjU1ZmE2MWZhOGQxNWRjNWE3MjYwNzEyNGFjOGU4NDkwNzUxZmYyNyJ9fX0="
|
||||
),
|
||||
VILLAGER_LIBRARIAN_TAIGA(//
|
||||
"Taiga Librarian Villager", "villager.taiga.librarian",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTg4MjA1MTAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjcxNzYyYzg5Mzk2OWQyN2U3Njk5YjgzNWViODU5ZTIxOTk2YzM2NDUwM2Q4NzBlNTQ1MTBiY2JmOGUzOWFmYiJ9fX0="
|
||||
),
|
||||
VILLAGER_MASON_TAIGA(
|
||||
"Taiga Mason Villager", "villager.taiga.mason",
|
||||
"eyJ0aW1lc3RhbXAiOjE1Nzc2NzQ2NzI4MDMsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDZkZmIwNGVjYTQ5NmU1MjQ3NjNlMjg4Y2YxY2Q1MzZmNGNjN2U5ZmY4MjJlYjI3OWVjZmU3YmU2N2JjYWMzOSJ9fX0="
|
||||
),
|
||||
VILLAGER_NITWIT_TAIGA(//
|
||||
"Taiga Nitwit Villager", "villager.taiga.nitwit",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQzOTk1NTYzMDIsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjhhOGMzNDk1OTA3MTVhNmZkNDFhMTc3MDI4MzNlMjdlMThhODFmNGQ2ZGM1Njk4MWUwNTEyNDU5MGUyMGUwYSJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_TAIGA(//
|
||||
"Taiga Villager", "villager.taiga.none",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDAwOTI0MjYsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWE5OTZlNmZiODdkNDAzODU1ODIxODAzYjYwODc3OTRhMTEwMjA2MGIyYjA2NGY1NmQwMDg4YjliMDhmMTk4MiJ9fX0="
|
||||
),
|
||||
VILLAGER_SHEPHERD_TAIGA(//
|
||||
"Taiga Sheperd Villager", "villager.taiga.sheperd",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDA4ODg3NDIsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjRkNWI2YjQ2OTQ0MzBmNzA2OGQxMDFkNWU4YWE4OTdkM2Q2NjUwODYwNWZiY2ZjNjRkZDNkOTcyYmM0NTUyYyJ9fX0="
|
||||
),
|
||||
VILLAGER_TOOLSMITH_TAIGA(//
|
||||
"Taiga Toolsmith Villager", "villager.taiga.toolsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDEzMDcwNTUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFlMmRkNzQ4ZDk2MTkyYTU4N2FjODU0M2ZiZWZjYTQ2MjgyYWQwMDgxMGZhMzM0OTdlZmZlMGM5ZDU2NzhiMCJ9fX0="
|
||||
),
|
||||
VILLAGER_WEAPONSMITH_TAIGA(
|
||||
"Taiga Weaponsmith Villager", "villager.taiga.weaponsmith",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDE4NzgzMjcsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTUxMzMxMzE4N2RiM2MwOWJlYzc4NzU1NzdmZmY2ZGM0YjYxZDlmZDA3NDMwZmRhOTBmNzhiOTUwYjQwOTY2OCJ9fX0="
|
||||
),
|
||||
/**
|
||||
"Plains Weaponsmith Villager", "villager.plains.weaponsmith", "e5d0f43c-58d7-4bf0-afc9-ed7a1ab73a8c",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWIxZWE1NGI3ZmQ5M2ZlNmMzNmQwYjVkODE1YWIwZGI4OWRiODk0ZGI3NWNlMGZjZTczOGU5NGVlOGI3OWUxOSJ9fX0="
|
||||
),
|
||||
|
||||
VILLAGER_ARMORER_DESERT(//
|
||||
"Desert Armorer Villager", "villager.desert.armorer", "28af2ba5-de7d-452b-8028-8e9bdb4b231a",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWI2N2EwZmI1MGYyOGM2ODhiZTk3ZDEyN2NmZTQwNTQ3ZDE4N2U4MjliZDI5MTUwMjA1MzNjZmU5M2JhMDRhIn19fQ=="
|
||||
),
|
||||
VILLAGER_BUTCHER_DESERT(//
|
||||
"Desert Butcher Villager", "villager.desert.butcher", "a8db08e1-4b3f-4d0c-be93-b646903032e3",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzFhNzAzZjY0NzA0M2UwY2U5ZjAzYzQyOGQxM2EwYTZmZWY0NWUzMGE3MzMxN2ViMTIxY2ZiZjFmYjg4YzE5NyJ9fX0="
|
||||
),
|
||||
VILLAGER_CARTOGRAPHER_DESERT(//
|
||||
"Desert Cartographer Villager", "villager.desert.cartographer", "df957172-1c07-48af-b3ee-252b9fa80f7f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmY5NDY3Y2QzNTc0ZTNiNjUwNDJiZjIxZjM2OWRhNjBmNzc3ODMyNzVkNDkzMGQzZTBkODI2MWI4YjUyOTc3MyJ9fX0="
|
||||
),
|
||||
VILLAGER_CLERIC_DESERT(//
|
||||
"Desert Cleric Villager", "villager.desert.cleric", "3f37a7fc-9881-42c9-b356-90c84cea760d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTE0NWViMDM5ODljMTA0MDFhYzdhM2U0ZWE4MTY1MmFjM2MxZDg4NTM3NTA4NThiY2ZiZDhmOTQyYmU5NTI5ZiJ9fX0="
|
||||
),
|
||||
VILLAGER_FARMER_DESERT(//
|
||||
"Desert Farmer Villager", "villager.desert.farmer", "c98bbc1d-5e0c-4a3e-94ec-339da6ceb6fa",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODZmYjM4OGY3MGNkMjQ5Yzk4YWQ2MTcwZThjOWIzNzU3NjY3MWQ3NzFjZDhmNzJkOWYxNzMwYjhjOWNhMjMyNSJ9fX0="
|
||||
),
|
||||
VILLAGER_FISHERMAN_DESERT(//
|
||||
"Desert Fisherman Villager", "villager.desert.fisherman", "7bcdbd9d-0235-4d6e-8041-90bac45318cc",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmQ1NDk1NDNhMTg2NTc5NGE4N2YwMDI1YjZmOWJiZWU3ZmM3OGNiYmI0ZThhZWVmYTFjMzdmODU3MzRlNDAxOCJ9fX0="
|
||||
),
|
||||
VILLAGER_FLETCHER_DESERT(//
|
||||
"Desert Fletcher Villager", "villager.desert.fletcher", "bbf415db-7b53-4d9c-9e5d-06e6f81c2286",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGJiMjBmMjljY2NlZWEwNzA3M2I4NDY4NGIzOTA5NjMwZGQxMTVhNDdkMmZlYzdjM2QyZjhiY2I5OTkyZTEwZCJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_DESERT(
|
||||
"Desert Leatherworker Villager", "villager.desert.leatherworker", "987bf436-578e-45bd-bf49-1af0681b86f1",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODgzZTliYzgyN2U3MzFhYTFkODAxNDg3ZTViNmEzOTE2YWQ0NTJkZGMyMDY4ZmFiMDdlOTdlYmM5MDM2ZTA1MiJ9fX0="
|
||||
),
|
||||
VILLAGER_LIBRARIAN_DESERT(//
|
||||
"Desert Librarian Villager", "villager.desert.librarian", "939fd80a-4c34-4bf4-9050-a57844a33d06",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjljMzA4M2JkMjQ5MGVlNDExZTAyZTE1MDliZDRmYzhiZjU0ZjkwZTkzMmI0YzU0NGE1YzEwNzg4MzA1NzhhYyJ9fX0="
|
||||
),
|
||||
VILLAGER_MASON_DESERT(
|
||||
"Desert Mason Villager", "villager.desert.mason", "2eb4ff3b-54ec-4697-9dde-836749e3fb31",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGRkODUxNTJlMzk5ZDMwMGM4NmRkYjRkZWUxNDIzNGJmODM2M2ZiYTE3NjQyZGI0MjE5ZTM3ODJhZjE5OGM4ZCJ9fX0="
|
||||
),
|
||||
VILLAGER_NITWIT_DESERT(//
|
||||
"Desert Nitwit Villager", "villager.desert.nitwit", "85085a91-b0b1-458f-93fd-2a9c7485a649",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjNkZDYxZjQxODRkY2Q0Y2YxMDBiNjAyMTQxZDNjMmJiNmMyMjIxN2E3ZWQ4MjZhNzgxNWI1ODdkZWNhNTBiNyJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_DESERT(//
|
||||
"Desert Villager", "villager.desert.none", "ecd82373-83bb-4232-9c31-1dc8c789a305",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTMzOTM1MjdhZmE2ZjcyYmQxYjJkNTliOTU3Yzc0MDk1ZWViNDNjZjkzNzg0ZTAxZmM2NjdmMzkyNmFhNzU5ZSJ9fX0="
|
||||
),
|
||||
VILLAGER_SHEPHERD_DESERT(//
|
||||
"Desert Sheperd Villager", "villager.desert.sheperd", "e1cb8198-d0be-4484-b160-38533d3e0590",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzM5ZTEwNzVmNjhiZDVhYmM1ZWY5NjllMzA4NTZjODU5MjgzNTc4MGYwM2FhZjViMmY1OTYyMTZmYWIwMDI2YiJ9fX0="
|
||||
),
|
||||
VILLAGER_TOOLSMITH_DESERT(//
|
||||
"Desert Toolsmith Villager", "villager.desert.toolsmith", "0a8b3bee-3867-4dac-ada5-8962741a885f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTE0ZGJmNDYzMGQ0YTFmMTA5ZWE3YWYwZDAyNDc4OGVmMTQyNWJkYjg5OWMxYWUxNDA4Y2UzZjlmZTRiMmRmMyJ9fX0="
|
||||
),
|
||||
VILLAGER_WEAPONSMITH_DESERT(
|
||||
"Desert Weaponsmith Villager", "villager.desert.weaponsmith", "5265f792-2484-4c3d-8819-bab6fc8a7046",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjFiZDhlYjMwMDkzYzkxZDA2NzVmNzMyMWY5NWFkOTFkNjk1ZjRhMmNjNmIxZTk2MzcyOTk4ZGUyNGQ2NmI2OSJ9fX0="
|
||||
),
|
||||
VILLAGER_ARMORER_JUNGLE(//
|
||||
"Jungle Armorer Villager", "villager.jungle.armorer", "af40e80c-8d4c-4df4-8ac3-7f83fe43b438",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjFkNTk5ODM1OTQ0NDc2ODk4MzAxODI2MDkyNjU3OTJlZGYxZTM1ZTlkMzYyYWQ2MmRiOWNmNzY5ZWE3MTVhMiJ9fX0="
|
||||
),
|
||||
VILLAGER_BUTCHER_JUNGLE(//
|
||||
"Jungle Butcher Villager", "villager.jungle.butcher", "9db68563-7fdb-4e51-8982-a8aa3079d238",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzFhNzAzZjY0NzA0M2UwY2U5ZjAzYzQyOGQxM2EwYTZmZWY0NWUzMGE3MzMxN2ViMTIxY2ZiZjFmYjg4YzE5NyJ9fX0="
|
||||
),
|
||||
VILLAGER_CARTOGRAPHER_JUNGLE(//
|
||||
"Jungle Cartographer Villager", "villager.jungle.cartographer", "a00a562d-b265-4937-ad95-56e1d35bf7bc",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmY5NDY3Y2QzNTc0ZTNiNjUwNDJiZjIxZjM2OWRhNjBmNzc3ODMyNzVkNDkzMGQzZTBkODI2MWI4YjUyOTc3MyJ9fX0="
|
||||
),
|
||||
VILLAGER_CLERIC_JUNGLE(//
|
||||
"Jungle Cleric Villager", "villager.jungle.cleric", "f590f4b6-665a-49a1-996c-6e6a4716bb69",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGEwZWYyYWRkMThhNDU3ZGY4YTk4ZWM1OTFiMGEwZGJkOTk0MmEyZDU4OTY1YTA0M2VhMDM5NzIwNDg3MTRmNSJ9fX0="
|
||||
),
|
||||
VILLAGER_FARMER_JUNGLE(//
|
||||
"Jungle Farmer Villager", "villager.jungle.farmer", "b88396a8-a5d3-4127-a2bb-dba8d420edea",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTQ5YmZjZTFkZTRkOWU3OGE3YTk2ODc3MzE5ZWRhOTBlOTg5YzI4YWZlMWI0YmYxZGM1NjNhNWQ0NGIxYWM3NCJ9fX0="
|
||||
),
|
||||
VILLAGER_FISHERMAN_JUNGLE(//
|
||||
"Jungle Fisherman Villager", "villager.jungle.fisherman", "f69bd527-6d52-4ba8-b20b-ac10ecf39fbc",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmU0M2MwYmYyNmVlMWE0MzMyYzExZTJjMjA4N2FhZDkwM2JlNDE4YWNhNTE0ZmQ4MGE3MDI4YjM3MWY1MzI4NyJ9fX0="
|
||||
),
|
||||
VILLAGER_FLETCHER_JUNGLE(//
|
||||
"Jungle Fletcher Villager", "villager.jungle.fletcher", "248b07f6-41bc-4346-bbf0-38e6e0250920",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjg0MjM4ZjA2YTg1YWM2NzY1MWQ5NmNmOTYzYzUyNTA1NTI5OTI5MGMzNDg4MjlhNjZjNDQ1OTdiYWY1NzQwYiJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_JUNGLE(
|
||||
"Jungle Leatherworker Villager", "villager.jungle.leatherworker", "fec3382a-446a-400a-9beb-6a89cf097cf8",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWEwOTU1ODdhYWZlMThjNWZlZTBiYWExNzk1ZmMyMjk0OGYyZGRjZGMzMmEzMzUwMzIzZDMzZGI1OTE4MDBlNiJ9fX0="
|
||||
),
|
||||
VILLAGER_LIBRARIAN_JUNGLE(//
|
||||
"Jungle Librarian Villager", "villager.jungle.librarian", "f7b45265-55f9-4177-8c16-f5056f4f03b5",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTJmYzNkMGU3Yjc0ZGY1N2NiNGJkNmM0MjZhYTM2MWY3NjIwMjk2ODUzMGU3NmNmZjU5YjM5MzQ3MTc5NTk4YiJ9fX0="
|
||||
),
|
||||
VILLAGER_MASON_JUNGLE(
|
||||
"Jungle Mason Villager", "villager.jungle.mason", "3d03efe3-3d28-4002-b7b6-c2ba565c376b",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTk2NzU2ZWU5MDNkMThkNTFhNWQ5NTk2M2I4NWJiYzEyYmI3YmQzOTEzZTg4NzE3ZDA2ZjhmOGU5YzU0MDFhYyJ9fX0="
|
||||
),
|
||||
VILLAGER_NITWIT_JUNGLE(//
|
||||
"Jungle Nitwit Villager", "villager.jungle.nitwit", "8fd6b95a-a26a-4688-ae35-531e4eb7b3da",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzFhZWY1MTNkYjdhYzJhZjViNmI4YzliOGUyYjlmNDYyMjgxNGQxNTFlNzUwNGQ5YWUyYzQ1ZjRkOTRlOTBhNiJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_JUNGLE(//
|
||||
"Jungle Villager", "villager.jungle.none", "0a9e8efb-9191-4c81-80f5-e27ca5433156",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTgwNmU5YTRkNzI4ZTcxNjgwM2ZjN2M3N2MxNTg2YzBkNWVkODViODZmNDA4MGI1YmRiNjQwY2M0N2YxNWI3ZCJ9fX0="
|
||||
),
|
||||
VILLAGER_SHEPHERD_JUNGLE(//
|
||||
"Jungle Sheperd Villager", "villager.jungle.sheperd", "ce2bdf44-297d-41ec-8fb6-63c6b6949712",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTk3NzY0MzBjZDIwYTY5YTFkODk5ZDlkMWRjZDMxZDdkMTM0MmI1NWU4MDE1YjdmMDYwZmIzYTJjMzM4YzhiYyJ9fX0="
|
||||
),
|
||||
VILLAGER_TOOLSMITH_JUNGLE(//
|
||||
"Jungle Toolsmith Villager", "villager.jungle.toolsmith", "c2ddbfa1-fc57-4b05-b0ea-27735b2dbf2a",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjg2MzVmOTFhYjhlOTU0MmQwNTAyODRmMDhkMGRjYTVkZjZjMWYzYmQ2ZDhhNzE0MjdkMTQxOWUzNzk5YzJiYyJ9fX0="
|
||||
),
|
||||
VILLAGER_WEAPONSMITH_JUNGLE(
|
||||
"Jungle Weaponsmith Villager", "villager.jungle.weaponsmith", "ef636711-2d3f-4431-a075-aacd858a682c",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjQ1ZmFiMzAzMjk0NGQxOGIyNjYyMWFkMjliM2Y5M2M0OTI3NmVkNmViNDY5ZWUyMTNhYmVjOGU0MmIyMjZhMiJ9fX0="
|
||||
),
|
||||
VILLAGER_ARMORER_SAVANNA(//
|
||||
"Savanna Armorer Villager", "villager.savanna.armorer", "95c3984d-4d67-4b09-9267-08191c12b669",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmU4YTBlZGQwODFmZTE3NjFhZDU0YzY3ODNjOWZjZDJkZjA2M2YzYzIyODc0MjBmYzZkMjkzOWRmY2Q3MDI0OSJ9fX0="
|
||||
),
|
||||
VILLAGER_BUTCHER_SAVANNA(//
|
||||
"Savanna Butcher Villager", "villager.savanna.butcher", "65803c56-c6ba-4725-95ee-0ccd87071f59",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTUxZTAwMzkxZjcxNGI1NTk5ZmQ4NTQ4NWE3NGZkM2MxOTkwY2VmMWJkMjgyMTBjZThmNTk2NjE4MDA4ZDVjYiJ9fX0="
|
||||
),
|
||||
VILLAGER_CARTOGRAPHER_SAVANNA(//
|
||||
"Savanna Cartographer Villager", "villager.savanna.cartographer", "e61975d2-8668-4244-a920-24b9986272b3",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjAxZWEzNzc2M2M4OTU5MzY3ZTNjM2FmOTM4YjU3YzU2NjI2OTMxMmM4YjBlY2VmMWY5ZjY0ZmQ4ZmE4YTkxOCJ9fX0="
|
||||
),
|
||||
VILLAGER_CLERIC_SAVANNA(//
|
||||
"Savanna Cleric Villager", "villager.savanna.cleric", "3781698f-f01e-4513-8da7-c9eb628eefea",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWIyY2JmZjE0ZjZiYTdmYjFjMjdkM2ZiZDYyOGI2MjM0NzUyNTMyMmJhMGY4ZWU5Y2EwZWIzNDkzYjg4Yjc2NCJ9fX0="
|
||||
),
|
||||
VILLAGER_FARMER_SAVANNA(//
|
||||
"Savanna Farmer Villager", "villager.savanna.farmer", "c27750ca-ef49-464e-b8a0-0507b7d90fe8",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzc0OGM3Yjk5MGFkMjMzNWFjNTU5MWQ4ZWNiYzYxZGRjNjdhMzU4YTcwN2VkMWIyNmUyYmFmMjM5YTcwZGEwOSJ9fX0="
|
||||
),
|
||||
VILLAGER_FISHERMAN_SAVANNA(//
|
||||
"Savanna Fisherman Villager", "villager.savanna.fisherman", "1959d4b5-4ffd-48ee-a3f8-c6a53ba9b067",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTkzZDQ5NzljMDU0NGI2ZGQxNjNhMjBjODZlM2E0NjZhN2ExMDI4NDA5M2QwZGMzMTNlOWY3ZGUyMGZlZTRlZiJ9fX0="
|
||||
),
|
||||
VILLAGER_FLETCHER_SAVANNA(//
|
||||
"Savanna Fletcher Villager", "villager.savanna.fletcher", "80173e34-dba5-4809-a43d-320b228e567c",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzAyODEyZmU3ZTA3NTI0MTEyMDkxYTI5ZTBiOTE1MmNkMmEyZmJmOTRhYTlhN2EyMTkzYzRkOGE3M2RjNzNmMSJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_SAVANNA(
|
||||
"Savanna Leatherworker Villager", "villager.savanna.leatherworker", "bf9ac4c7-585f-452a-82c7-16c85cfb2b3a",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjVhN2U2YThlZGVlZjc0ZGM1ODQzOGQ3MDZmYjJhZWQ4ZWNiZWI0ZjlhNGQ5NTY2MGY1ZmY1MDZlNGFmM2Q1In19fQ=="
|
||||
),
|
||||
VILLAGER_LIBRARIAN_SAVANNA(//
|
||||
"Savanna Librarian Villager", "villager.savanna.librarian", "f7ed8ecf-0162-42aa-8840-5a5544873b96",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTNjNTQ3NmJmYTMxYWY4YTQ2NDliNjc5NzY1MjhiMzAxZmY5YjhiYTU3NWE4YzgxYzlmMDlmMzhiNjkyNzgxZSJ9fX0="
|
||||
),
|
||||
VILLAGER_MASON_SAVANNA(
|
||||
"Savanna Mason Villager", "villager.savanna.mason", "82259e14-9ed7-4a92-b3eb-4d01a0864f7a",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQwNWZkMTNkNGU3ODYwNzUxMmZmNzE2OWYzZWQ1NmIzMTA0MjM5M2QzMDlhYzhlODIzNjZlMTE3OGJiYTVjMiJ9fX0="
|
||||
),
|
||||
VILLAGER_NITWIT_SAVANNA(//
|
||||
"Savanna Nitwit Villager", "villager.savanna.nitwit", "c670fbae-98e7-41f3-bfdd-321218dcb5ff",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjE0N2MzMTVlMzg1ZmRlMWFmZjI5MmMwNGEzNzM5MGE2ODNlZGQ0NTYxMGU1OThmOTBjOWExYThhNTY3YjJmNSJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_SAVANNA(//
|
||||
"Savanna Villager", "villager.savanna.none", "531fe1ca-24e1-4851-9971-acb678cdef26",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTQ3MGIyNTE2ODhiYTU4MDc3NDIwOWQ1MjY2NDAwMmYzMDk3MzRkYzljOWMyMTZmMGQ3MTY3ZjNkYmRhZGVjMCJ9fX0="
|
||||
),
|
||||
VILLAGER_SHEPHERD_SAVANNA(//
|
||||
"Savanna Sheperd Villager", "villager.savanna.sheperd", "83581234-bd51-4f52-ac7f-496d092e7fea",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDczMTgxYzA0NzNiN2IxMTExYTVkYmFiMmQyNDQzNzI5ZTdiZmQ4NDk5YjEyZmZlODdhYWYxZTExM2IyYWEyOSJ9fX0="
|
||||
),
|
||||
VILLAGER_TOOLSMITH_SAVANNA(//
|
||||
"Savanna Toolsmith Villager", "villager.savanna.toolsmith", "8d032c47-42a8-4778-a1c0-1924ce5449b2",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGQ4YzBlZjEzMGZiNWIxZDcxNjlhY2M4NThhOGU3ZGNlMzM2NjI5YWNmN2JmODhkMzE2MmNiNDA5YjQ5NzE0MCJ9fX0="
|
||||
),
|
||||
VILLAGER_WEAPONSMITH_SAVANNA(
|
||||
"Savanna Weaponsmith Villager", "villager.savanna.weaponsmith", "c74c6dce-ce0b-4267-baee-b502b55653c9",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzc0MmE0ZGJiYjgwZWRhZDk2MmM3NThmYjc0NmEyMzYzOTYzODdhMDIzNzA2NDVhYWZjOGM0NDJjOThlMjk3ZiJ9fX0="
|
||||
),
|
||||
VILLAGER_ARMORER_SNOW(//
|
||||
"Snow Armorer Villager", "villager.snow.armorer", "1a9ae0b9-ab32-4f01-9af9-4d0b1ed9f428",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmEwODUxMGI1ZjYwNjlkOTQ4OGFkY2FmMDc4OTViM2U3OWEzMTViMTlhYWYwMTM5NTQ5NDkyMmE2ZjlkYTdhZiJ9fX0="
|
||||
),
|
||||
VILLAGER_BUTCHER_SNOW(//
|
||||
"Snow Butcher Villager", "villager.snow.butcher", "07841184-4b23-4de9-8d86-94faa672fe86",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzFhNzAzZjY0NzA0M2UwY2U5ZjAzYzQyOGQxM2EwYTZmZWY0NWUzMGE3MzMxN2ViMTIxY2ZiZjFmYjg4YzE5NyJ9fX0="
|
||||
),
|
||||
VILLAGER_CARTOGRAPHER_SNOW(//
|
||||
"Snow Cartographer Villager", "villager.snow.cartographer", "cbbfcde1-7dc5-4b99-ad03-e991e40b032e",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2JkNDM5NjZmYjNmN2M3NDA2OGNmYjRjOGM4OWU4NjJhNWNkZWMzNDk5NWMxMjI4NTk2NzVlOGQ5ZjlmNGMwZiJ9fX0="
|
||||
),
|
||||
VILLAGER_CLERIC_SNOW(//
|
||||
"Snow Cleric Villager", "villager.snow.cleric", "14c643d6-f288-4fd0-9968-5e97ba4aa4ee",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWUwMjNkMWE5ZGVhODM0OGIxM2Y0YzFlZDI2YmM3MWNlZWQ1N2VkYmEwNTZjYjc3NTI4ODc1YzUwNDMxYmFmYSJ9fX0="
|
||||
),
|
||||
VILLAGER_FARMER_SNOW(//
|
||||
"Snow Farmer Villager", "villager.snow.farmer", "e2c33986-5783-4f6d-be18-c75600773ac1",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2M0OTEyYmNiOTY0NmQ5MjkyYzZhNzIwZTU0Nzc1NDE2MTVlNDg0MjQxZTE3NDU0NzcwY2I0ZGRhMzBlM2FlMyJ9fX0="
|
||||
),
|
||||
VILLAGER_FISHERMAN_SNOW(//
|
||||
"Snow Fisherman Villager", "villager.snow.fisherman", "dff05a7b-9724-4891-a0a8-ce713cbcedde",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTBmMWVjNzEwZmFhMzhiYWUzZTc5NTE5NjEzODkyNTQ1ZjM0ZTRlZDM4N2ZhZGEyZDdkODA0YmM5ZDg0NjUwMiJ9fX0="
|
||||
),
|
||||
VILLAGER_FLETCHER_SNOW(//
|
||||
"Snow Fletcher Villager", "villager.snow.fletcher", "e17a9dcb-a93f-4032-ab1b-04b0a55028f8",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzY1NDcwYTM1NzU1ZTU1OGI2MzNmZDM0ZTEwOGFhNTYyMDJhYjNlZDU5NmNmNGYxOTQ3ZTk3YTEzMmU1MDNjNyJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_SNOW(
|
||||
"Snow Leatherworker Villager", "villager.snow.leatherworker", "bac6f170-0849-4dde-b13c-535e8e8d2683",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDM1MjMwNDFhMjE2M2Y3MTY5NDFjZGE3MjcxMzhiOTgxMzdhZTRmNzU3ZjNlNzFlOGIwYzFiMmEyOGQ3ZTZiYSJ9fX0="
|
||||
),
|
||||
VILLAGER_LIBRARIAN_SNOW(//
|
||||
"Snow Librarian Villager", "villager.snow.librarian", "6a374869-79d5-4b69-a74d-17b9d6a3745a",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWI5NmIwNmM3ODZhOTAwNjI4MTgwNDVjYzZlMTNmNWI3MTA0NjQ5MTg0MDFiYzVhMjExODZiOWZjNGM4NGYzYiJ9fX0="
|
||||
),
|
||||
VILLAGER_MASON_SNOW(
|
||||
"Snow Mason Villager", "villager.snow.mason", "d4698632-f271-4efb-807b-0d22390d4217",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGUyYThlNjRmYzBlYjIxZDNlMjNkMWQxZGU0ZThiODA2MmQ3NGI4NjY3NTliYzk2OGYxMzA5NmRmYWUzYzM4YiJ9fX0="
|
||||
),
|
||||
VILLAGER_NITWIT_SNOW(//
|
||||
"Snow Nitwit Villager", "villager.snow.nitwit", "8c1c3dd8-7921-4cee-a843-594285e7dfda",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzRhYTk1ODc3NDAxNWQ3N2UwM2Q5Mjg1ZDcxYTI4NzY5NDUxNWU3N2RjZmYzYjAwNjBlYjg1NjU4YWZmYzU3NiJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_SNOW(//
|
||||
"Snow Villager", "villager.snow.none", "b88666ac-efc7-49ef-a6bd-51db174ed605",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzRiYWNjOTBlYTFjNGQ4ZjBiOGQ4YjkzMTY1NWY0ZWM0OTFkYmY1OGYwNTIzNzJmNDQ5MDkyZWY1YTkxNDIzNyJ9fX0="
|
||||
),
|
||||
VILLAGER_SHEPHERD_SNOW(//
|
||||
"Snow Sheperd Villager", "villager.snow.sheperd", "2663f068-b88d-4a9e-b389-bac5ded550a5",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2U5YzI5YTJhYjkxOWE5N2Y4NGEwYjVlMGFkYjA0NTEzZWJlZmExNzRjM2IwZDcyNWI4NGNlNDgyNjkzZjdjZCJ9fX0="
|
||||
),
|
||||
VILLAGER_TOOLSMITH_SNOW(//
|
||||
"Snow Toolsmith Villager", "villager.snow.toolsmith", "13dc3b0e-c95c-478d-9272-18c9a144880e",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmEzZTA5MjI2ZWNkNTM2ZDZjNThiNTQ5NzkwZTFmYTdlOTMyNjAyOGE3MDM3MDUyOTIxYTAwNDI2Y2FmMTBlYSJ9fX0="
|
||||
),
|
||||
VILLAGER_WEAPONSMITH_SNOW(
|
||||
"Snow Weaponsmith Villager", "villager.snow.weaponsmith", "ae80f2f6-558f-4e14-97d8-6c818babbcca",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDkyNjZhZGZjYWRiYjBiODY5YjEwZTIyNjQwOWMwODNjNmRjN2EwNzE5YTZjODA4Y2JjMjM2NzY1YWI4YzBlZSJ9fX0="
|
||||
),
|
||||
VILLAGER_ARMORER_SWAMP(//
|
||||
"Swamp Armorer Villager", "villager.swamp.armorer", "ba517ac7-b732-45c4-a940-1fa2ef5fa864",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzE4NDBlNDA4MmY0YWVhYTY5NTM1NDg0YTdhYjdkOGY3ZTEzYzVjNTc4OWEyYTM4M2JkN2U4N2IzODc5MDZjNSJ9fX0="
|
||||
),
|
||||
VILLAGER_BUTCHER_SWAMP(//
|
||||
"Swamp Butcher Villager", "villager.swamp.butcher", "c1470a6a-4635-4a67-9f69-231ea893e7b4",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjUyNmZhYTQ2NmRkMzcxNjhhYWMxYzYwY2JjN2U1YTI0MDVjOTM1MDcxZGVhNmNjMWUzYjllYWJmODdlYmExYyJ9fX0="
|
||||
),
|
||||
VILLAGER_CARTOGRAPHER_SWAMP(//
|
||||
"Swamp Cartographer Villager", "villager.swamp.cartographer", "43860f33-abb2-462c-8b04-62b898cb7a88",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDIwNWVkM2Q4MmRjNTI1MDExZWMzOTIwODA5MTY1MDVmZjg2Y2E5NjE3YWQwZjJjNzI5NmI5OTA3ZmEyZmI4YiJ9fX0="
|
||||
),
|
||||
VILLAGER_CLERIC_SWAMP(//
|
||||
"Swamp Cleric Villager", "villager.swamp.cleric", "7f73a0d6-f9d5-4849-abf2-b2fd792d4991",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGM0Mjk2NDg2Y2NlYzgxYWNkZjIxNDUxYzY5MGIyMzRiYzlmZGFjNWFiNmVmZDU0NTFhYjVjZGFmYWZiNzk3OSJ9fX0="
|
||||
),
|
||||
VILLAGER_FARMER_SWAMP(//
|
||||
"Swamp Farmer Villager", "villager.swamp.farmer", "1c26bd8c-6fea-45df-a1c7-687a48ab839e",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzQ4ZDVmODA4NDc4NTRlOGNkNTU2ZjE4NDdjZTM3M2E5OGJiYzdkZDAyMzJiNmUyMDY0NzQyNDQxMTk2NDg5NiJ9fX0="
|
||||
),
|
||||
VILLAGER_FISHERMAN_SWAMP(//
|
||||
"Swamp Fisherman Villager", "villager.swamp.fisherman", "324a9f09-4c86-450c-989a-421198b42249",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODMyZTk4ZmM1ZDc3OGE0ZTM0ZDU1OTc2MWQ1YWY0YTYzYjJlMTZlZDkxZmE3N2E1NDJhZDdmNDlmZjA0MTM1MCJ9fX0="
|
||||
),
|
||||
VILLAGER_FLETCHER_SWAMP(//
|
||||
"Swamp Fletcher Villager", "villager.swamp.fletcher", "1ea813a0-2921-4f3f-b6c1-e4783b232cc4",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmQ0ODQ0ZmUyZmI4N2QxNzEzMDY5MjU2MjRkYmM5ZjVjZGNmOGYyYTJjYjlkYjI1ZTJiNzdhMjc3OTAyYmFhZCJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_SWAMP(
|
||||
"Swamp Leatherworker Villager", "villager.swamp.leatherworker", "3542f7b3-e263-4a21-a67b-302af77a57c9",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTMzNGQ3OWY4ZmI0MjAzZDRiZmFhYWM4ZDU5NTVmZTA5NjVkY2JiMDMzNmVmMTY3NTc1NjdlMWQwODQyYjhhMyJ9fX0="
|
||||
),
|
||||
VILLAGER_LIBRARIAN_SWAMP(//
|
||||
"Swamp Librarian Villager", "villager.swamp.librarian", "ad599620-65b0-4932-bd96-1307bd160942",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDI0MzU3ZWVkMGEzYTM5NGEyNmJkZjhmYzhlNjEzZTgzNjE5NmE3MmE1OTRkNWUwYWFiNmYzMDcyM2NjNDRkNCJ9fX0="
|
||||
),
|
||||
VILLAGER_MASON_SWAMP(
|
||||
"Swamp Mason Villager", "villager.swamp.mason", "f0e90655-0b2c-4281-af5f-9c76edfa8e04",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTMzNGQ3OWY4ZmI0MjAzZDRiZmFhYWM4ZDU5NTVmZTA5NjVkY2JiMDMzNmVmMTY3NTc1NjdlMWQwODQyYjhhMyJ9fX0="
|
||||
),
|
||||
VILLAGER_NITWIT_SWAMP(//
|
||||
"Swamp Nitwit Villager", "villager.swamp.nitwit", "29147086-eb71-437a-bc23-a35612119e3d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzNmMGE2ZmRkNTkxNmRlNjhmN2Q5ZGM5ZmY5ZGQ5YWFkNWM3ZjNmMWQyYmJmNzJiOTU2YWQ0NTMzZTJkNmU1ZSJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_SWAMP(//
|
||||
"Swamp Villager", "villager.swamp.none", "d8fcd176-507e-4eaf-9d3b-e956aac5e211",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTU1MWE0OTlmN2FiMTc3YmE0M2FjYTQxZGZkOGZjNDExYjFkMWU1MDJhMzQ2ZjljNGQ2MGI3YTVlNTdmNDM2YyJ9fX0="
|
||||
),
|
||||
VILLAGER_SHEPHERD_SWAMP(//
|
||||
"Swamp Sheperd Villager", "villager.swamp.sheperd", "27461b58-8e1e-4dbc-a898-8655bb57e77a",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDU0NWM0MWY3NGU1OThiYjE0ZDRlMTUyNGRhMzg1ZDU0YTRhZjYxMDA5YmM5MGRlYTA3MGZhY2NjZjMwYzViMiJ9fX0="
|
||||
),
|
||||
VILLAGER_TOOLSMITH_SWAMP(//
|
||||
"Swamp Toolsmith Villager", "villager.swamp.toolsmith", "17c01e16-ae97-4738-8536-1f2892fcf069",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmM0YjE4Mzk4MWU0ODUxNDYxZTdiYjljNzEwY2Y4ZTViNjU3NWZiMjI0YzJhYzBjNmU1Y2FkM2MyYTVkMmY5OSJ9fX0="
|
||||
),
|
||||
VILLAGER_WEAPONSMITH_SWAMP(
|
||||
"Swamp Weaponsmith Villager", "villager.swamp.weaponsmith", "c30f8885-38c2-4933-bf3b-71e27771b61b",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTUwZjUxNzkxNjBmYTM1NDU0NzUyOTM1MDI2YmViY2Q5ODc1MTk5Njc1MGY1NGVjNWY5NTNhY2I4N2NiZWJjOSJ9fX0="
|
||||
),
|
||||
VILLAGER_ARMORER_TAIGA(//
|
||||
"Taiga Armorer Villager", "villager.taiga.armorer", "451d1524-c582-4ffa-afb0-4bd8d2586dd2",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2YxYmE0MTQ1NGZjNTVkZGUwNzlmYzE1YmYyMTQ2MTg5MWQ1YjVkMDNkZDQwMTZhZTdjZGViNDZhOGZjODQwNCJ9fX0="
|
||||
),
|
||||
VILLAGER_BUTCHER_TAIGA(//
|
||||
"Taiga Butcher Villager", "villager.taiga.butcher", "b2f48a4c-6b6d-4718-8a5a-257f91ec116d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjI4ODdhMGZmNzg5YTdmY2FiOGU3NzhlNzEwZGJhZDBkOTYxZWJiYWFmYTVlZTA0MGUyMTM1YzVkM2E4Y2M3MiJ9fX0="
|
||||
),
|
||||
VILLAGER_CARTOGRAPHER_TAIGA(//
|
||||
"Taiga Cartographer Villager", "villager.taiga.cartographer", "4db86d7e-f9e2-4962-b61f-2e84d07d1653",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzA4OWZiMjQ2YWEyZjNlZjI3NGQwMTQyOWQzNTM0NzE5ZTQyYjFhODE1MWNkYWMzMDM1NGQ0OTY3YjczYTc4MCJ9fX0="
|
||||
),
|
||||
VILLAGER_CLERIC_TAIGA(//
|
||||
"Taiga Cleric Villager", "villager.taiga.cleric", "7c507bcd-766a-4c11-8724-7104cae126f3",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2M1ZGVhOTljMjg2NzE4NTczOGJlMDJiNzFjYWNmMmNkYTRhMjczYzExNDliZTdhNTE2NGRhNzJmMGY5NDZmNyJ9fX0="
|
||||
),
|
||||
VILLAGER_FARMER_TAIGA(//
|
||||
"Taiga Farmer Villager", "villager.taiga.farmer", "d1893e4b-b62f-49ed-8ccb-5d4f6a283c65",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTU3ZjM4M2IwYmRiNDU2OTU3Y2ZiY2M1MmIyODA4YTBmOGEwMGMzNTlkMTVhZWIwMTNmNTYzNGZhMDAzNzkyIn19fQ=="
|
||||
),
|
||||
VILLAGER_FISHERMAN_TAIGA(//
|
||||
"Taiga Fisherman Villager", "villager.taiga.fisherman", "a2eb3270-0257-427e-9889-5e92852b0fec",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWI5YzZlZGI1YzBiYTU0YjIwM2RiZjA0ODI3M2M0YmFkYjE1Y2VjMWQzMjI4NjUwZDJjMmZlNWIzZmFiM2NiYiJ9fX0="
|
||||
),
|
||||
VILLAGER_FLETCHER_TAIGA(//
|
||||
"Taiga Fletcher Villager", "villager.taiga.fletcher", "649921fd-8bef-4986-8386-e2590c401259",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDllMTVmODQ4YjUwODMyMGRiZjE2NGJmMGQ0YmFjODlkNTE3MWYxODZiZWViNDFjN2JkMzQ2MDExYzg3YmQ4YiJ9fX0="
|
||||
),
|
||||
VILLAGER_LEATHERWORKER_TAIGA(
|
||||
"Taiga Leatherworker Villager", "villager.taiga.leatherworker", "e70b3715-29a1-4b6f-a839-93d217ea53ba",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2VhNTI0ZjM3ZjYyYmI1YWQyMWYyZmEzNjU1ZmE2MWZhOGQxNWRjNWE3MjYwNzEyNGFjOGU4NDkwNzUxZmYyNyJ9fX0="
|
||||
),
|
||||
VILLAGER_LIBRARIAN_TAIGA(//
|
||||
"Taiga Librarian Villager", "villager.taiga.librarian", "099b6827-bad3-43e2-9b31-de60e7647e90",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjcxNzYyYzg5Mzk2OWQyN2U3Njk5YjgzNWViODU5ZTIxOTk2YzM2NDUwM2Q4NzBlNTQ1MTBiY2JmOGUzOWFmYiJ9fX0="
|
||||
),
|
||||
VILLAGER_MASON_TAIGA(
|
||||
"Taiga Mason Villager", "villager.taiga.mason", "4b262358-041a-41e0-9db9-da8d20b0b1d6",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDZkZmIwNGVjYTQ5NmU1MjQ3NjNlMjg4Y2YxY2Q1MzZmNGNjN2U5ZmY4MjJlYjI3OWVjZmU3YmU2N2JjYWMzOSJ9fX0="
|
||||
),
|
||||
VILLAGER_NITWIT_TAIGA(//
|
||||
"Taiga Nitwit Villager", "villager.taiga.nitwit", "254ad245-7348-4681-8306-e3aef9f40b0e",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjhhOGMzNDk1OTA3MTVhNmZkNDFhMTc3MDI4MzNlMjdlMThhODFmNGQ2ZGM1Njk4MWUwNTEyNDU5MGUyMGUwYSJ9fX0="
|
||||
),
|
||||
VILLAGER_NONE_TAIGA(//
|
||||
"Taiga Villager", "villager.taiga.none", "7b8fbb6c-e6aa-4b66-bf85-6e9439ea8563",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWE5OTZlNmZiODdkNDAzODU1ODIxODAzYjYwODc3OTRhMTEwMjA2MGIyYjA2NGY1NmQwMDg4YjliMDhmMTk4MiJ9fX0="
|
||||
),
|
||||
VILLAGER_SHEPHERD_TAIGA(//
|
||||
"Taiga Sheperd Villager", "villager.taiga.sheperd", "4308f5e7-591c-4f60-904b-690f445f2785",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjRkNWI2YjQ2OTQ0MzBmNzA2OGQxMDFkNWU4YWE4OTdkM2Q2NjUwODYwNWZiY2ZjNjRkZDNkOTcyYmM0NTUyYyJ9fX0="
|
||||
),
|
||||
VILLAGER_TOOLSMITH_TAIGA(//
|
||||
"Taiga Toolsmith Villager", "villager.taiga.toolsmith", "5bffb69b-616b-49bb-a024-b338abc54e9d",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFlMmRkNzQ4ZDk2MTkyYTU4N2FjODU0M2ZiZWZjYTQ2MjgyYWQwMDgxMGZhMzM0OTdlZmZlMGM5ZDU2NzhiMCJ9fX0="
|
||||
),
|
||||
VILLAGER_WEAPONSMITH_TAIGA(
|
||||
"Taiga Weaponsmith Villager", "villager.taiga.weaponsmith", "1f2a4e15-4ebe-4183-84bc-181dc8e33045",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTUxMzMxMzE4N2RiM2MwOWJlYzc4NzU1NzdmZmY2ZGM0YjYxZDlmZDA3NDMwZmRhOTBmNzhiOTUwYjQwOTY2OCJ9fX0="
|
||||
),
|
||||
/**
|
||||
VILLAGER_(
|
||||
|
||||
|
||||
|
||||
|
||||
""
|
||||
),
|
||||
*/
|
||||
;
|
||||
//private final UUID owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
VillagerHeads(String name, String nameString, String texture){
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(VillagerHeads verbosity : VillagerHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) )
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
*/
|
||||
;
|
||||
private final String owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
VillagerHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.owner = ownerUUID;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(VillagerHeads verbosity : VillagerHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) ) {
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the owner
|
||||
*/
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getTexture() {
|
||||
return texture;
|
||||
}
|
||||
@@ -469,7 +473,7 @@ public enum VillagerHeads {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
@@ -478,5 +482,5 @@ public enum VillagerHeads {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -4,118 +4,104 @@ import java.util.UUID;
|
||||
|
||||
public enum ZombieVillagerHeads {
|
||||
// Zombie Villager variants
|
||||
ZOMBIE_VILLAGER_ARMORER(
|
||||
"Zombie Armorer", "zombie_villager.armorer",
|
||||
"7cfb4bb2-3205-42fb-afd6-70fd580fb8a5",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDg2Nzc3NjgsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZhYmY1OWIxMTg3MzRkMzI4ZWQ0YjkwMDVhYTRhMzI1NzE3YjRhMzkyZjM5OWViMmRhNGYxMWEwZjVlM2E4OSJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_BUTCHER(
|
||||
"Zombie Butcher", "zombie_villager.butcher",
|
||||
"6c399981-91ff-4d93-b283-ca9af1228382",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDg3NjU5MjAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzAxZDhiNDcxNmE5ZGE0NWVlNGEzZTRjMmE4Njg0NmFkMWQ3NWE5NzNlYmVlMTgzZjE5YWRjZmI3YTRiYmM2ZiJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_CARTOGRAPHER(
|
||||
"Zombie Cartographer", "zombie_villager.cartographer",
|
||||
"be6c92ff-fd94-4d56-b9ca-20f0050f3b41",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDg4MjU4ODgsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGU3YjJmYTVmNmE4MjYxZGM0MzhmMmE0YzE1OTc3YTkxM2ZhNmNjMTRmZTk5ZjQ3ZWJmNzcxN2I3YzJiZDA4ZiJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_CLERIC(
|
||||
"Zombie Cleric", "zombie_villager.cleric",
|
||||
"26a97cfb-4cbc-4f75-b847-8d41201abd49",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDg4ODMxMTAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmEwNWY3ZWFmNjkxYjRhYjc0MTc0MDUyNGNjMjMwYTcwYTNlY2UxZTRjNWFjMmRjNzhlNmYwOGRmOWUzODBhNiJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_FARMER(
|
||||
"Zombie Farmer", "zombie_villager.farmer",
|
||||
"469641b7-ec99-4a62-b597-c7da85426aae",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDg5Mzk0MzIsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjZkZTg4NWMwMzFhYjkwZTcyMmFhMTNkZjg2N2E3NGI4Yzg4NTZhMjkwZWEwOTViNDJiNjQ3ZDdiYzMwZDEzOSJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_FISHERMAN(
|
||||
"Zombie Fisherman", "zombie_villager.fisherman",
|
||||
"1812010d-e392-4c3c-b468-6c9066e26c1b",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDg5OTY4NTAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjFkNGQyMjZkMzk2NWJhZWM0NTFhMTFlMDE2YzVlN2EwOTUxMTRjNDRhYmY1MmUzNGRjNDQ4YWJmZmJhYjI2ZiJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_FLETCHER(
|
||||
"Zombie Fletcher", "zombie_villager.fletcher",
|
||||
"7d20b4d0-05c1-468d-a0fd-e4d8673f9c6e",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDkwNDgzMDgsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTgxOThjZmFmMWExOTIzY2E2MmZmYWY5OTUyOTE2YmE5MzgyNzkxZjBjN2VhZjhiNmQ4MDRlNmMxZTJmNDE0ZiJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_LEATHERWORKER(
|
||||
"Zombie Leatherworker", "zombie_villager.leatherworker",
|
||||
"87b57113-d8ca-4fa4-8214-ea6896e2ce4f",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDkxNzQ2OTMsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzlkZjRmYjY3Yjk1OGEzNzViODg0ZWVlNjMwNTM3ZjhmYmQzOWZiY2I3MzczOTgzMzRjNTg2YTA4NDNmMjdkZiJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_LIBRARIAN(
|
||||
"Zombie Librarian", "zombie_villager.librarian",
|
||||
"2069d306-ad23-4bb9-a6d0-d9e2f57757e6",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDkyMzU1OTAsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTQzZDg0ZDdjMTk5MDBjODUzY2RkODBmZTJlNWE1YzQxZTVjM2U2ODNjNzUzYTgxZDZiOWM0ZTZiNDdkNjU4ZSJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_MASON(
|
||||
"Zombie Mason", "zombie_villager.Mason",
|
||||
"87b57113-d8ca-4fa4-8214-ea6896e2ce4f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmI1NTJjOTBmMjEyZTg1NWQxMjI1NWQ1Y2Q2MmVkMzhiOWNkN2UzMGU3M2YwZWE3NzlkMTc2NDMzMGU2OTI2NCJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_NITWIT(
|
||||
"Zombie Nitwit", "zombie_villager.nitwit",
|
||||
"87b57113-d8ca-4fa4-8214-ea6896e2ce4f",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDkzMDkwMzksInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk3MjlhMDgzZTQ4OGExNTEwMGIyYmIxOWVjZTVlZmYzY2MzZmVmYzIzMGI5NzI2NGI3M2U3MTk3NTkwZTI1MyJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_NONE(
|
||||
"Zombie Villager", "zombie_villager.none",
|
||||
"87b57113-d8ca-4fa4-8214-ea6896e2ce4f",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDkzNzM2MDEsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjdjZTM4Yjk5YzBlNTgxZGY3ZmJlYmYzMWM3NjM3ZjYyNDI1ZGRlMjg1MDhmZWU1OTU3ODE4MTU4OTFhZmQ2In19fQ=="
|
||||
),
|
||||
ZOMBIE_VILLAGER_SHEPHERD(
|
||||
"Zombie Shepherd", "zombie_villager.shepherd",
|
||||
"47f729f2-a01c-46c8-982b-82d2ac59437f",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDk0NDMyNjQsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTc2NjI4ZGU3ZjUyZjhjNTM2YmZjZDJiMzAwMGEyODJiN2Q1OGY0NjI0NTgxYmEwMGVkZmYwNWRiYWRkZmFhNyJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_TOOLSMITH(
|
||||
"Zombie Toolsmith", "zombie_villager.toolsmith",
|
||||
"87b57113-d8ca-4fa4-8214-ea6896e2ce4f",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDk1MTc1MDEsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGVlNTczMmNhMmYxYmIwYmVkYmNiYzk0ODIwYzBmMDE1OTRlNjY4ZWZiZTFjOGQ2OGM3MDEzMDE3NTMxNjcwYyJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_WEAPONSMITH(
|
||||
"Zombie Weaponsmith", "zombie_villager.weaponsmith",
|
||||
"920e0f3f-f4f4-4b99-8eac-509a974a1393",
|
||||
"eyJ0aW1lc3RhbXAiOjE1ODQ0MDk1ODMwMDUsInByb2ZpbGVJZCI6IjVlNmUzNDRkYmY3ODRiZmU5NjQ2YWRkNjc1YjcyMTVmIiwicHJvZmlsZU5hbWUiOiJKb2VsR29kT2ZXYXIiLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWYxZmYzZTc0MDQ0NjczYzkxOTA2MDEyZTI0YzY3NmZmMjA1OGEzZWE5ZjM2NTMzN2FlOWI0YjkwZTg1OTgwIn19fQ=="
|
||||
),
|
||||
/**
|
||||
ZOMBIE_VILLAGER_ARMORER(
|
||||
"Zombie Armorer", "zombie_villager.armorer", "7cfb4bb2-3205-42fb-afd6-70fd580fb8a5",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZhYmY1OWIxMTg3MzRkMzI4ZWQ0YjkwMDVhYTRhMzI1NzE3YjRhMzkyZjM5OWViMmRhNGYxMWEwZjVlM2E4OSJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_BUTCHER(
|
||||
"Zombie Butcher", "zombie_villager.butcher", "6c399981-91ff-4d93-b283-ca9af1228382",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzAxZDhiNDcxNmE5ZGE0NWVlNGEzZTRjMmE4Njg0NmFkMWQ3NWE5NzNlYmVlMTgzZjE5YWRjZmI3YTRiYmM2ZiJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_CARTOGRAPHER(
|
||||
"Zombie Cartographer", "zombie_villager.cartographer", "be6c92ff-fd94-4d56-b9ca-20f0050f3b41",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGU3YjJmYTVmNmE4MjYxZGM0MzhmMmE0YzE1OTc3YTkxM2ZhNmNjMTRmZTk5ZjQ3ZWJmNzcxN2I3YzJiZDA4ZiJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_CLERIC(
|
||||
"Zombie Cleric", "zombie_villager.cleric", "26a97cfb-4cbc-4f75-b847-8d41201abd49",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmEwNWY3ZWFmNjkxYjRhYjc0MTc0MDUyNGNjMjMwYTcwYTNlY2UxZTRjNWFjMmRjNzhlNmYwOGRmOWUzODBhNiJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_FARMER(
|
||||
"Zombie Farmer", "zombie_villager.farmer", "469641b7-ec99-4a62-b597-c7da85426aae",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjZkZTg4NWMwMzFhYjkwZTcyMmFhMTNkZjg2N2E3NGI4Yzg4NTZhMjkwZWEwOTViNDJiNjQ3ZDdiYzMwZDEzOSJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_FISHERMAN(
|
||||
"Zombie Fisherman", "zombie_villager.fisherman", "1812010d-e392-4c3c-b468-6c9066e26c1b",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjFkNGQyMjZkMzk2NWJhZWM0NTFhMTFlMDE2YzVlN2EwOTUxMTRjNDRhYmY1MmUzNGRjNDQ4YWJmZmJhYjI2ZiJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_FLETCHER(
|
||||
"Zombie Fletcher", "zombie_villager.fletcher", "7d20b4d0-05c1-468d-a0fd-e4d8673f9c6e",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTgxOThjZmFmMWExOTIzY2E2MmZmYWY5OTUyOTE2YmE5MzgyNzkxZjBjN2VhZjhiNmQ4MDRlNmMxZTJmNDE0ZiJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_LEATHERWORKER(
|
||||
"Zombie Leatherworker", "zombie_villager.leatherworker", "87b57113-d8ca-4fa4-8214-ea6896e2ce4f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzlkZjRmYjY3Yjk1OGEzNzViODg0ZWVlNjMwNTM3ZjhmYmQzOWZiY2I3MzczOTgzMzRjNTg2YTA4NDNmMjdkZiJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_LIBRARIAN(
|
||||
"Zombie Librarian", "zombie_villager.librarian", "2069d306-ad23-4bb9-a6d0-d9e2f57757e6",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTQzZDg0ZDdjMTk5MDBjODUzY2RkODBmZTJlNWE1YzQxZTVjM2U2ODNjNzUzYTgxZDZiOWM0ZTZiNDdkNjU4ZSJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_MASON(
|
||||
"Zombie Mason", "zombie_villager.Mason", "87b57113-d8ca-4fa4-8214-ea6896e2ce4f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmI1NTJjOTBmMjEyZTg1NWQxMjI1NWQ1Y2Q2MmVkMzhiOWNkN2UzMGU3M2YwZWE3NzlkMTc2NDMzMGU2OTI2NCJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_NITWIT(
|
||||
"Zombie Nitwit", "zombie_villager.nitwit", "87b57113-d8ca-4fa4-8214-ea6896e2ce4f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk3MjlhMDgzZTQ4OGExNTEwMGIyYmIxOWVjZTVlZmYzY2MzZmVmYzIzMGI5NzI2NGI3M2U3MTk3NTkwZTI1MyJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_NONE(
|
||||
"Zombie Villager", "zombie_villager.none", "87b57113-d8ca-4fa4-8214-ea6896e2ce4f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjdjZTM4Yjk5YzBlNTgxZGY3ZmJlYmYzMWM3NjM3ZjYyNDI1ZGRlMjg1MDhmZWU1OTU3ODE4MTU4OTFhZmQ2In19fQ=="
|
||||
),
|
||||
ZOMBIE_VILLAGER_SHEPHERD(
|
||||
"Zombie Shepherd", "zombie_villager.shepherd", "47f729f2-a01c-46c8-982b-82d2ac59437f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTc2NjI4ZGU3ZjUyZjhjNTM2YmZjZDJiMzAwMGEyODJiN2Q1OGY0NjI0NTgxYmEwMGVkZmYwNWRiYWRkZmFhNyJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_TOOLSMITH(
|
||||
"Zombie Toolsmith", "zombie_villager.toolsmith", "87b57113-d8ca-4fa4-8214-ea6896e2ce4f",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGVlNTczMmNhMmYxYmIwYmVkYmNiYzk0ODIwYzBmMDE1OTRlNjY4ZWZiZTFjOGQ2OGM3MDEzMDE3NTMxNjcwYyJ9fX0="
|
||||
),
|
||||
ZOMBIE_VILLAGER_WEAPONSMITH(
|
||||
"Zombie Weaponsmith", "zombie_villager.weaponsmith", "920e0f3f-f4f4-4b99-8eac-509a974a1393",
|
||||
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWYxZmYzZTc0MDQ0NjczYzkxOTA2MDEyZTI0YzY3NmZmMjA1OGEzZWE5ZjM2NTMzN2FlOWI0YjkwZTg1OTgwIn19fQ=="
|
||||
),
|
||||
/**
|
||||
VILLAGER_(
|
||||
"",
|
||||
"",
|
||||
""
|
||||
),
|
||||
*/
|
||||
;
|
||||
private final UUID owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
ZombieVillagerHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
if(ownerUUID == null){
|
||||
ownerUUID = UUID.randomUUID().toString();
|
||||
}
|
||||
this.owner = UUID.fromString(ownerUUID);
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(ZombieVillagerHeads verbosity : ZombieVillagerHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) )
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
*/
|
||||
;
|
||||
private final String owner;
|
||||
private final String texture;
|
||||
private final String name;
|
||||
private final String nameString;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public UUID getOwner() {
|
||||
ZombieVillagerHeads(String name, String nameString, String ownerUUID, String texture){
|
||||
if(ownerUUID == null){
|
||||
ownerUUID = UUID.randomUUID().toString();
|
||||
}
|
||||
this.owner = ownerUUID;
|
||||
this.texture = texture;
|
||||
this.name = name;
|
||||
this.nameString = nameString;
|
||||
}
|
||||
|
||||
public static final String getNameFromTexture(String texture)
|
||||
{
|
||||
//MoreMobHeads.logger.info("texture=" + texture);
|
||||
for(ZombieVillagerHeads verbosity : ZombieVillagerHeads.values())
|
||||
{
|
||||
//MoreMobHeads.logger.info(verbosity.getName() + "=" + verbosity.getTexture());
|
||||
if(verbosity.getTexture().contains(texture) ) {
|
||||
return verbosity.getNameString() ;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@@ -126,7 +112,7 @@ public enum ZombieVillagerHeads {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -5,15 +5,14 @@ import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.github.joelgodofwar.mmh.MoreMobHeads;
|
||||
|
||||
public class ConfigAPI {
|
||||
|
||||
public final static Logger logger = Logger.getLogger("Minecraft");
|
||||
|
||||
public static void CheckForConfig(Plugin plugin){
|
||||
|
||||
public void CheckForConfig(MoreMobHeads plugin){
|
||||
try{
|
||||
if(!plugin.getDataFolder().exists()){
|
||||
log(": Data Folder doesn't exist");
|
||||
@@ -27,33 +26,33 @@ public class ConfigAPI {
|
||||
log("config.yml not found, creating!");
|
||||
plugin.saveDefaultConfig();
|
||||
FileConfiguration config = plugin.getConfig();
|
||||
|
||||
|
||||
config.options().copyDefaults(true);
|
||||
plugin.saveConfig();
|
||||
}
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Reloadconfig(Plugin plugin){
|
||||
|
||||
public static void Reloadconfig(MoreMobHeads plugin){
|
||||
// Load config.
|
||||
FileConfiguration config = plugin.getConfig();
|
||||
String daString = config.getString("debug").replace("'", "") + ",";
|
||||
|
||||
|
||||
if(daString.contains("true")){
|
||||
MoreMobHeads.debug = true;
|
||||
plugin.debug = true;
|
||||
}else{
|
||||
MoreMobHeads.debug = false;
|
||||
plugin.debug = false;
|
||||
}
|
||||
String daString2 = config.getString("auto_update_check").replace("'", "") + ",";
|
||||
if(daString2.contains("true")){
|
||||
MoreMobHeads.UpdateCheck = true;
|
||||
plugin.UpdateCheck = true;
|
||||
}else{
|
||||
MoreMobHeads.UpdateCheck = false;
|
||||
plugin.UpdateCheck = false;
|
||||
}
|
||||
|
||||
if(MoreMobHeads.debug){log("UpdateCheck = " + MoreMobHeads.UpdateCheck);} //TODO: Logger
|
||||
|
||||
if(plugin.debug){log("UpdateCheck = " + plugin.UpdateCheck);} //TODO: Logger
|
||||
}
|
||||
public static void log(String dalog){
|
||||
Bukkit.getLogger().info(dalog);
|
||||
|
||||
@@ -0,0 +1,558 @@
|
||||
package com.github.joelgodofwar.mmh.util;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
//This class is where all formatting methods are stored.
|
||||
@SuppressWarnings("unused")
|
||||
public class Format {
|
||||
//private static MineverseChat plugin = MineverseChat.getInstance();
|
||||
|
||||
public static final int LEGACY_COLOR_CODE_LENGTH = 2;
|
||||
public static final int HEX_COLOR_CODE_LENGTH = 14;
|
||||
public static final String DEFAULT_COLOR_CODE = String.valueOf(ChatColor.WHITE);
|
||||
public static final String HEX_COLOR_CODE_PREFIX = "#";
|
||||
public static final String BUKKIT_COLOR_CODE_PREFIX = "�";
|
||||
public static final String BUKKIT_HEX_COLOR_CODE_PREFIX = "x";
|
||||
|
||||
/**public static String convertToJson(MineverseChatPlayer sender, String format, String chat) {
|
||||
JsonFormat JSONformat = MineverseChat.jfInfo.getJsonFormat(sender.getJsonFormat());
|
||||
String f = format.replace("\\", "\\\\").replace("\"", "\\\"");
|
||||
String c = chat.replace("\\", "\\\\").replace("\"", "\\\"");
|
||||
String json = "[\"\",{\"text\":\"\",\"extra\":[";
|
||||
String prefix = "";
|
||||
String suffix = "";
|
||||
try {
|
||||
prefix = FormatStringAll(MineverseChat.chat.getPlayerPrefix(sender.getPlayer()));
|
||||
suffix = FormatStringAll(MineverseChat.chat.getPlayerSuffix(sender.getPlayer()));
|
||||
if(suffix.equals("")) {
|
||||
suffix = "venturechat_no_suffix_code";
|
||||
}
|
||||
if(prefix.equals("")) {
|
||||
prefix = "venturechat_no_prefix_code";
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
System.out.println("Exception?" + e.getLocalizedMessage());
|
||||
if(plugin.getConfig().getString("loglevel", "info").equals("debug")) {
|
||||
Bukkit.getConsoleSender().sendMessage(Format.FormatStringAll("&8[&eVentureChat&8]&e - Prefix and / or suffix don't exist, setting to nothing."));
|
||||
}
|
||||
suffix = "venturechat_no_suffix_code";
|
||||
prefix = "venturechat_no_prefix_code";
|
||||
}
|
||||
String nickname = "";
|
||||
if(sender.getPlayer() != null) {
|
||||
nickname = FormatStringAll(sender.getPlayer().getDisplayName());
|
||||
}
|
||||
json += convertPlaceholders(f, JSONformat, prefix, nickname, suffix, sender);
|
||||
json += "]}";
|
||||
json += "," + convertLinks(c);
|
||||
json += "]";
|
||||
if(plugin.getConfig().getString("loglevel", "info").equals("debug")) {
|
||||
System.out.println(json);
|
||||
System.out.println("END OF JSON");
|
||||
System.out.println("END OF JSON");
|
||||
System.out.println("END OF JSON");
|
||||
System.out.println("END OF JSON");
|
||||
System.out.println("END OF JSON");
|
||||
}
|
||||
return json;
|
||||
}*/
|
||||
|
||||
/**private static String convertPlaceholders(String s, JsonFormat format, String prefix, String nickname, String suffix, MineverseChatPlayer icp) {
|
||||
String remaining = s;
|
||||
String temp = "";
|
||||
int indexStart = -1;
|
||||
int indexEnd = -1;
|
||||
String placeholder = "";
|
||||
String lastCode = "�f";
|
||||
do {
|
||||
Pattern pattern = Pattern.compile("(" + escapeAllRegex(prefix) + "|" + escapeAllRegex(nickname) + "|" + escapeAllRegex(suffix) + ")");
|
||||
Matcher matcher = pattern.matcher(remaining);
|
||||
if(matcher.find()) {
|
||||
indexStart = matcher.start();
|
||||
indexEnd = matcher.end();
|
||||
placeholder = remaining.substring(indexStart, indexEnd);
|
||||
temp += convertToJsonColors(lastCode + remaining.substring(0, indexStart)) + ",";
|
||||
lastCode = getLastCode(lastCode + remaining.substring(0, indexStart));
|
||||
String action = "";
|
||||
String text = "";
|
||||
String hover = "";
|
||||
if(placeholder.contains(prefix)) {
|
||||
action = format.getClickPrefix();
|
||||
text = PlaceholderAPI.setBracketPlaceholders(icp.getPlayer(), format.getClickPrefixText());
|
||||
for(String st : format.getHoverTextPrefix()) {
|
||||
hover += Format.FormatStringAll(st) + "\n";
|
||||
}
|
||||
}
|
||||
if(placeholder.contains(nickname)) {
|
||||
action = format.getClickName();
|
||||
text = PlaceholderAPI.setBracketPlaceholders(icp.getPlayer(), format.getClickNameText());
|
||||
for(String st : format.getHoverTextName()) {
|
||||
hover += Format.FormatStringAll(st) + "\n";
|
||||
}
|
||||
}
|
||||
if(placeholder.contains(suffix)) {
|
||||
action = format.getClickSuffix();
|
||||
text = PlaceholderAPI.setBracketPlaceholders(icp.getPlayer(), format.getClickSuffixText());
|
||||
for(String st : format.getHoverTextSuffix()) {
|
||||
hover += Format.FormatStringAll(st) + "\n";
|
||||
}
|
||||
}
|
||||
hover = PlaceholderAPI.setBracketPlaceholders(icp.getPlayer(), hover.substring(0, hover.length() - 1));
|
||||
temp += convertToJsonColors(lastCode + placeholder, ",\"clickEvent\":{\"action\":\"" + action + "\",\"value\":\"" + text + "\"},\"hoverEvent\":{\"action\":\"show_text\",\"value\":{\"text\":\"\",\"extra\":[" + convertToJsonColors(hover) + "]}}") + ",";
|
||||
lastCode = getLastCode(lastCode + placeholder);
|
||||
remaining = remaining.substring(indexEnd);
|
||||
}
|
||||
else {
|
||||
temp += convertToJsonColors(lastCode + remaining);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(true);
|
||||
return temp;
|
||||
}*/
|
||||
|
||||
/**private static String convertLinks(String s) {
|
||||
String remaining = s;
|
||||
String temp = "";
|
||||
int indexLink = -1;
|
||||
int indexLinkEnd = -1;
|
||||
String link = "";
|
||||
String lastCode = "�f";
|
||||
do {
|
||||
Pattern pattern = Pattern.compile("([a-zA-Z0-9�\\-:/]+\\.[a-zA-Z/0-9�\\-:_#]+(\\.[a-zA-Z/0-9.�\\-:#\\?\\+=_]+)?)");
|
||||
Matcher matcher = pattern.matcher(remaining);
|
||||
if(matcher.find()) {
|
||||
indexLink = matcher.start();
|
||||
indexLinkEnd = matcher.end();
|
||||
link = remaining.substring(indexLink, indexLinkEnd);
|
||||
temp += convertToJsonColors(lastCode + remaining.substring(0, indexLink)) + ",";
|
||||
lastCode = getLastCode(lastCode + remaining.substring(0, indexLink));
|
||||
String https = "";
|
||||
if(ChatColor.stripColor(link).contains("https://"))
|
||||
https = "s";
|
||||
temp += convertToJsonColors(lastCode + link, ",\"underlined\":\"" + underlineURLs() + "\",\"clickEvent\":{\"action\":\"open_url\",\"value\":\"http" + https + "://" + ChatColor.stripColor(link.replace("http://", "").replace("https://", "")) + "\"},\"hoverEvent\":{\"action\":\"show_text\",\"value\":{\"text\":\"\",\"extra\":[" + convertToJsonColors(lastCode + link) + "]}}") + ",";
|
||||
lastCode = getLastCode(lastCode + link);
|
||||
remaining = remaining.substring(indexLinkEnd);
|
||||
}
|
||||
else {
|
||||
temp += convertToJsonColors(lastCode + remaining);
|
||||
break;
|
||||
}
|
||||
}
|
||||
while(true);
|
||||
return temp;
|
||||
}*/
|
||||
|
||||
public static String getLastCode(String s) {
|
||||
String ts = "";
|
||||
char[] ch = s.toCharArray();
|
||||
for(int a = 0; a < s.length() - 1; a ++) {
|
||||
if(String.valueOf(ch[a + 1]).matches("[lkomnLKOMN]") && ch[a] == '�') {
|
||||
ts += String.valueOf(ch[a]) + ch[a + 1];
|
||||
a ++;
|
||||
}
|
||||
else if(String.valueOf(ch[a + 1]).matches("[0123456789abcdefrABCDEFR]") && ch[a] == '�') {
|
||||
ts = String.valueOf(ch[a]) + ch[a + 1];
|
||||
a ++;
|
||||
}
|
||||
else if(ch[a + 1] == 'x' && ch[a] == '�') {
|
||||
if(ch.length > a + 13) {
|
||||
if(String.valueOf(ch[a + 3]).matches("[0123456789abcdefABCDEF]") && String.valueOf(ch[a + 5]).matches("[0123456789abcdefABCDEF]") && String.valueOf(ch[a + 7]).matches("[0123456789abcdefABCDEF]") && String.valueOf(ch[a + 9]).matches("[0123456789abcdefABCDEF]") && String.valueOf(ch[a + 11]).matches("[0123456789abcdefABCDEF]") && String.valueOf(ch[a + 13]).matches("[0123456789abcdefABCDEF]") && ch[a + 2] == '�' && ch[a + 4] == '�' && ch[a + 6] == '�' && ch[a + 8] == '�' && ch[a + 10] == '�' && ch[a + 12] == '�') {
|
||||
ts = String.valueOf(ch[a]) + ch[a + 1] + ch[a + 2] + ch[a + 3] + ch[a + 4] + ch[a + 5] + ch[a + 6] + ch[a + 7] + ch[a + 8] + ch[a + 9] + ch[a + 10] + ch[a + 11] + ch[a + 12] + ch[a + 13];
|
||||
a += 13;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
private static String convertToJsonColors(String s) {
|
||||
return convertToJsonColors(s, "");
|
||||
}
|
||||
|
||||
private static String convertToJsonColors(String s, String extensions) {
|
||||
String remaining = s;
|
||||
String temp = "";
|
||||
int indexColor = -1;
|
||||
int indexNextColor = -1;
|
||||
String color = "";
|
||||
String modifier = "";
|
||||
boolean bold = false;
|
||||
boolean obfuscated = false;
|
||||
boolean italic = false;
|
||||
boolean strikethrough = false;
|
||||
boolean underlined = false;
|
||||
String previousColor = "";
|
||||
int colorLength = LEGACY_COLOR_CODE_LENGTH;
|
||||
do {
|
||||
if(remaining.length() < LEGACY_COLOR_CODE_LENGTH) {
|
||||
temp = "{\"text\":\"" + remaining + "\"},";
|
||||
break;
|
||||
}
|
||||
modifier = "";
|
||||
indexColor = remaining.indexOf(BUKKIT_COLOR_CODE_PREFIX);
|
||||
previousColor = color;
|
||||
|
||||
color = remaining.substring(1, indexColor + LEGACY_COLOR_CODE_LENGTH);
|
||||
if(color.equals(BUKKIT_HEX_COLOR_CODE_PREFIX)) {
|
||||
if(remaining.length() >= HEX_COLOR_CODE_LENGTH) {
|
||||
color = HEX_COLOR_CODE_PREFIX + remaining.substring(LEGACY_COLOR_CODE_LENGTH, indexColor + HEX_COLOR_CODE_LENGTH).replace(BUKKIT_COLOR_CODE_PREFIX, "");
|
||||
colorLength = HEX_COLOR_CODE_LENGTH;
|
||||
bold = false;
|
||||
obfuscated = false;
|
||||
italic = false;
|
||||
strikethrough = false;
|
||||
underlined = false;
|
||||
}
|
||||
}
|
||||
else if(!color.matches("[0123456789abcdefABCDEF]")) {
|
||||
switch(color) {
|
||||
case "l":
|
||||
case "L": {
|
||||
bold = true;
|
||||
break;
|
||||
}
|
||||
case "k":
|
||||
case "K": {
|
||||
obfuscated = true;
|
||||
break;
|
||||
}
|
||||
case "o":
|
||||
case "O": {
|
||||
italic = true;
|
||||
break;
|
||||
}
|
||||
case "m":
|
||||
case "M": {
|
||||
strikethrough = true;
|
||||
break;
|
||||
}
|
||||
case "n":
|
||||
case "N": {
|
||||
underlined = true;
|
||||
break;
|
||||
}
|
||||
case "r":
|
||||
case "R": {
|
||||
bold = false;
|
||||
obfuscated = false;
|
||||
italic = false;
|
||||
strikethrough = false;
|
||||
underlined = false;
|
||||
color = "f";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!color.equals("f"))
|
||||
color = previousColor;
|
||||
if(color.length() == 0)
|
||||
color = "f";
|
||||
}
|
||||
else {
|
||||
bold = false;
|
||||
obfuscated = false;
|
||||
italic = false;
|
||||
strikethrough = false;
|
||||
underlined = false;
|
||||
}
|
||||
if(bold)
|
||||
modifier += ",\"bold\":\"true\"";
|
||||
if(obfuscated)
|
||||
modifier += ",\"obfuscated\":\"true\"";
|
||||
if(italic)
|
||||
modifier += ",\"italic\":\"true\"";
|
||||
if(underlined)
|
||||
modifier += ",\"underlined\":\"true\"";
|
||||
if(strikethrough)
|
||||
modifier += ",\"strikethrough\":\"true\"";
|
||||
remaining = remaining.substring(colorLength);
|
||||
colorLength = LEGACY_COLOR_CODE_LENGTH;
|
||||
indexNextColor = remaining.indexOf(BUKKIT_COLOR_CODE_PREFIX);
|
||||
if(indexNextColor == -1) {
|
||||
indexNextColor = remaining.length();
|
||||
}
|
||||
temp += "{\"text\":\"" + remaining.substring(0, indexNextColor) + "\",\"color\":\"" + hexidecimalToJsonColorRGB(color) + "\"" + modifier + extensions + "},";
|
||||
remaining = remaining.substring(indexNextColor);
|
||||
}
|
||||
while(remaining.length() > 1 && indexColor != -1);
|
||||
if(temp.length() > 1)
|
||||
temp = temp.substring(0, temp.length() - 1);
|
||||
return temp;
|
||||
}
|
||||
|
||||
private static String hexidecimalToJsonColorRGB(String c) {
|
||||
if(c.length() == 1) {
|
||||
switch(c) {
|
||||
case "0": return "black";
|
||||
case "1": return "dark_blue";
|
||||
case "2": return "dark_green";
|
||||
case "3": return "dark_aqua";
|
||||
case "4": return "dark_red";
|
||||
case "5": return "dark_purple";
|
||||
case "6": return "gold";
|
||||
case "7": return "gray";
|
||||
case "8": return "dark_gray";
|
||||
case "9": return "blue";
|
||||
case "a":
|
||||
case "A": return "green";
|
||||
case "b":
|
||||
case "B": return "aqua";
|
||||
case "c":
|
||||
case "C": return "red";
|
||||
case "d":
|
||||
case "D": return "light_purple";
|
||||
case "e":
|
||||
case "E": return "yellow";
|
||||
case "f":
|
||||
case "F": return "white";
|
||||
default: return "white";
|
||||
}
|
||||
}
|
||||
if(isValidHexColor(c)) {
|
||||
return c;
|
||||
}
|
||||
return "white";
|
||||
}
|
||||
|
||||
/**public static String convertPlainTextToJson(String s, boolean convertURL) {
|
||||
if(convertURL) {
|
||||
return "[" + Format.convertLinks(s) + "]";
|
||||
}
|
||||
else {
|
||||
return "[" + convertToJsonColors("�f" + s) + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/**public static String formatModerationGUI(String json, Player player, String sender, String channelName, int hash) {
|
||||
if(player.hasPermission("venturechat.gui")) {
|
||||
json = json.substring(0, json.length() - 1);
|
||||
json += "," + Format.convertToJsonColors(Format.FormatStringAll(plugin.getConfig().getString("guiicon")), ",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/vchatgui " + sender + " " + channelName + " " + hash +"\"},\"hoverEvent\":{\"action\":\"show_text\",\"value\":{\"text\":\"\",\"extra\":[" + Format.convertToJsonColors(Format.FormatStringAll(plugin.getConfig().getString("guitext"))) + "]}}") + "]";
|
||||
}
|
||||
return json;
|
||||
}*/
|
||||
|
||||
/**public static PacketContainer createPacketPlayOutChat(String json) {
|
||||
WrappedChatComponent component = WrappedChatComponent.fromJson(json);
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Server.CHAT);
|
||||
container.getModifier().writeDefaults();
|
||||
container.getChatComponents().write(0, component);
|
||||
return container;
|
||||
}
|
||||
|
||||
public static PacketContainer createPacketPlayOutChat(WrappedChatComponent component) {
|
||||
PacketContainer container = new PacketContainer(PacketType.Play.Server.CHAT);
|
||||
container.getModifier().writeDefaults();
|
||||
container.getChatComponents().write(0, component);
|
||||
return container;
|
||||
}
|
||||
|
||||
public static void sendPacketPlayOutChat(Player player, PacketContainer packet) {
|
||||
try {
|
||||
ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet);
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static String toPlainText(Object o, Class<?> c) {
|
||||
List<Object> finalList = new ArrayList<>();
|
||||
StringBuilder stringbuilder = new StringBuilder();
|
||||
try {
|
||||
splitComponents(finalList, o, c);
|
||||
for(Object component : finalList) {
|
||||
if(VersionHandler.is1_7_10()) {
|
||||
stringbuilder.append((String) component.getClass().getMethod("e").invoke(component));
|
||||
}
|
||||
else {
|
||||
stringbuilder.append((String) component.getClass().getMethod("getText").invoke(component));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if(plugin.getConfig().getString("loglevel", "info").equals("debug")) {
|
||||
System.out.println("my string");
|
||||
System.out.println("my string");
|
||||
System.out.println("my string");
|
||||
System.out.println("my string");
|
||||
System.out.println("my string");
|
||||
System.out.println(stringbuilder.toString());
|
||||
}
|
||||
return stringbuilder.toString();
|
||||
}
|
||||
|
||||
private static void splitComponents(List<Object> finalList, Object o, Class<?> c) throws Exception {
|
||||
if(plugin.getConfig().getString("loglevel", "info").equals("debug")) {
|
||||
for(Method m : c.getMethods()) {
|
||||
System.out.println(m.getName());
|
||||
}
|
||||
}
|
||||
if(VersionHandler.is1_7() || VersionHandler.is1_8() || VersionHandler.is1_9() || VersionHandler.is1_10() || VersionHandler.is1_11() || VersionHandler.is1_12() || VersionHandler.is1_13() || (VersionHandler.is1_14() && !VersionHandler.is1_14_4())) {
|
||||
ArrayList<?> list = (ArrayList<?>) c.getMethod("a").invoke(o, new Object[0]);
|
||||
for(Object component : list) {
|
||||
ArrayList<?> innerList = (ArrayList<?>) c.getMethod("a").invoke(component, new Object[0]);
|
||||
if(innerList.size() > 0) {
|
||||
splitComponents(finalList, component, c);
|
||||
}
|
||||
else {
|
||||
finalList.add(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ArrayList<?> list = (ArrayList<?>) c.getMethod("getSiblings").invoke(o, new Object[0]);
|
||||
for(Object component : list) {
|
||||
ArrayList<?> innerList = (ArrayList<?>) c.getMethod("getSiblings").invoke(component, new Object[0]);
|
||||
if(innerList.size() > 0) {
|
||||
splitComponents(finalList, component, c);
|
||||
}
|
||||
else {
|
||||
finalList.add(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
protected static Pattern chatHexColorPattern = Pattern.compile("(?i)&([X])");
|
||||
protected static Pattern chatColorPattern = Pattern.compile("(?i)&([0-9A-F])");
|
||||
protected static Pattern chatMagicPattern = Pattern.compile("(?i)&([K])");
|
||||
protected static Pattern chatBoldPattern = Pattern.compile("(?i)&([L])");
|
||||
protected static Pattern chatStrikethroughPattern = Pattern.compile("(?i)&([M])");
|
||||
protected static Pattern chatUnderlinePattern = Pattern.compile("(?i)&([N])");
|
||||
protected static Pattern chatItalicPattern = Pattern.compile("(?i)&([O])");
|
||||
protected static Pattern chatResetPattern = Pattern.compile("(?i)&([R])");
|
||||
|
||||
public static String FormatStringColor(String string) {
|
||||
String allFormated = string;
|
||||
allFormated = chatColorPattern.matcher(allFormated).replaceAll("\u00A7$1");
|
||||
allFormated = chatHexColorPattern.matcher(allFormated).replaceAll("\u00A7$1");
|
||||
allFormated = allFormated.replaceAll("%", "\\%");
|
||||
|
||||
allFormated = convertHexColorCodeStringToBukkitColorCodeString(allFormated);
|
||||
return allFormated;
|
||||
}
|
||||
|
||||
public static String FormatString(String string) {
|
||||
String allFormated = string;
|
||||
allFormated = chatMagicPattern.matcher(allFormated).replaceAll("\u00A7$1");
|
||||
allFormated = chatBoldPattern.matcher(allFormated).replaceAll("\u00A7$1");
|
||||
allFormated = chatStrikethroughPattern.matcher(allFormated).replaceAll("\u00A7$1");
|
||||
allFormated = chatUnderlinePattern.matcher(allFormated).replaceAll("\u00A7$1");
|
||||
allFormated = chatItalicPattern.matcher(allFormated).replaceAll("\u00A7$1");
|
||||
allFormated = chatResetPattern.matcher(allFormated).replaceAll("\u00A7$1");
|
||||
allFormated = allFormated.replaceAll("%", "\\%");
|
||||
return allFormated;
|
||||
}
|
||||
|
||||
public static String FormatStringAll(String string) {
|
||||
String allFormated = Format.FormatString(string);
|
||||
allFormated = Format.FormatStringColor(allFormated);
|
||||
return allFormated;
|
||||
}
|
||||
|
||||
public static String FormatPlayerName(String playerPrefix, String playerDisplayName, String playerSuffix) {
|
||||
playerPrefix = chatColorPattern.matcher(playerPrefix).replaceAll("\u00A7$1");
|
||||
playerPrefix = chatMagicPattern.matcher(playerPrefix).replaceAll("\u00A7$1");
|
||||
playerPrefix = chatBoldPattern.matcher(playerPrefix).replaceAll("\u00A7$1");
|
||||
playerPrefix = chatStrikethroughPattern.matcher(playerPrefix).replaceAll("\u00A7$1");
|
||||
playerPrefix = chatUnderlinePattern.matcher(playerPrefix).replaceAll("\u00A7$1");
|
||||
playerPrefix = chatItalicPattern.matcher(playerPrefix).replaceAll("\u00A7$1");
|
||||
playerPrefix = chatResetPattern.matcher(playerPrefix).replaceAll("\u00A7$1");
|
||||
|
||||
playerSuffix = chatColorPattern.matcher(playerSuffix).replaceAll("\u00A7$1");
|
||||
playerSuffix = chatMagicPattern.matcher(playerSuffix).replaceAll("\u00A7$1");
|
||||
playerSuffix = chatBoldPattern.matcher(playerSuffix).replaceAll("\u00A7$1");
|
||||
playerSuffix = chatStrikethroughPattern.matcher(playerSuffix).replaceAll("\u00A7$1");
|
||||
playerSuffix = chatUnderlinePattern.matcher(playerSuffix).replaceAll("\u00A7$1");
|
||||
playerSuffix = chatItalicPattern.matcher(playerSuffix).replaceAll("\u00A7$1");
|
||||
playerSuffix = chatResetPattern.matcher(playerSuffix).replaceAll("\u00A7$1");
|
||||
return playerPrefix + playerDisplayName.trim() + playerSuffix;
|
||||
}
|
||||
|
||||
/**public static String FilterChat(String msg) {
|
||||
int t = 0;
|
||||
List<String> filters = plugin.getConfig().getStringList("filters");
|
||||
for(String s : filters) {
|
||||
t = 0;
|
||||
String[] pparse = new String[2];
|
||||
pparse[0] = " ";
|
||||
pparse[1] = " ";
|
||||
StringTokenizer st = new StringTokenizer(s, ",");
|
||||
while(st.hasMoreTokens()) {
|
||||
if(t < 2) {
|
||||
pparse[t++] = st.nextToken();
|
||||
}
|
||||
}
|
||||
msg = msg.replaceAll("(?i)" + pparse[0], pparse[1]);
|
||||
}
|
||||
return msg;
|
||||
}*/
|
||||
|
||||
public static boolean isValidColor(String color) {
|
||||
Boolean bFound = false;
|
||||
for(ChatColor bkColors : ChatColor.values()) {
|
||||
if(color.equalsIgnoreCase(bkColors.name())) {
|
||||
bFound = true;
|
||||
}
|
||||
}
|
||||
return bFound;
|
||||
}
|
||||
|
||||
public static boolean isValidHexColor(String color) {
|
||||
Pattern pattern = Pattern.compile("(^#[0-9a-fA-F]{6}\\b)");
|
||||
Matcher matcher = pattern.matcher(color);
|
||||
return matcher.find();
|
||||
}
|
||||
|
||||
public static String convertHexColorCodeToBukkitColorCode(String color) {
|
||||
StringBuilder bukkitColorCode = new StringBuilder(BUKKIT_COLOR_CODE_PREFIX + BUKKIT_HEX_COLOR_CODE_PREFIX);
|
||||
for(int a = 1; a < color.length(); a++) {
|
||||
bukkitColorCode.append(BUKKIT_COLOR_CODE_PREFIX + color.charAt(a));
|
||||
}
|
||||
return bukkitColorCode.toString();
|
||||
}
|
||||
|
||||
public static String convertHexColorCodeStringToBukkitColorCodeString(String string) {
|
||||
Pattern pattern = Pattern.compile("(#[0-9a-fA-F]{6})");
|
||||
Matcher matcher = pattern.matcher(string);
|
||||
while(matcher.find()) {
|
||||
int indexStart = matcher.start();
|
||||
int indexEnd = matcher.end();
|
||||
String hexColor = string.substring(indexStart, indexEnd);
|
||||
String bukkitColor = convertHexColorCodeToBukkitColorCode(hexColor);
|
||||
string = string.replaceAll(hexColor, bukkitColor);
|
||||
matcher.reset(string);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
public static String escapeAllRegex(String input) {
|
||||
return input.replace("[", "\\[").replace("]", "\\]").replace("{", "\\{").replace("}", "\\}").replace("(", "\\(").replace(")", "\\)").replace("|", "\\|").replace("+", "\\+").replace("*", "\\*");
|
||||
}
|
||||
|
||||
/**public static boolean underlineURLs() {
|
||||
return plugin.getConfig().getBoolean("underlineurls", true);
|
||||
}*/
|
||||
public static final char colorChar = '\u00a7';
|
||||
//code taken from bukkit, so it can work on bungee too
|
||||
public static String color(String textToTranslate){
|
||||
if (textToTranslate == null) return null;
|
||||
if (!textToTranslate.contains("&")) return textToTranslate;
|
||||
char[] b = textToTranslate.toCharArray();
|
||||
for (int i = 0; i < b.length - 1; i++) {
|
||||
if ((b[i] == '&') && ("0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[(i + 1)]) > -1)){
|
||||
b[i] = colorChar;
|
||||
b[(i + 1)] = Character.toLowerCase(b[(i + 1)]);
|
||||
}
|
||||
}
|
||||
return new String(b);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,445 @@
|
||||
package com.github.joelgodofwar.mmh.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.Ordering;
|
||||
|
||||
/**
|
||||
* Determine the current Minecraft version.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public final class MinecraftVersion implements Comparable<MinecraftVersion>, Serializable {
|
||||
/**
|
||||
* The minimum version ProtocolLib has been tested with.
|
||||
*/
|
||||
public static final String MINIMUM_MINECRAFT_VERSION = "1.20";
|
||||
|
||||
/**
|
||||
* The maximum version ProtocolLib has been tested with.
|
||||
*/
|
||||
public static final String MAXIMUM_MINECRAFT_VERSION = "1.20.4";
|
||||
|
||||
/**
|
||||
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.20.4) was released.
|
||||
*/
|
||||
public static final String MINECRAFT_LAST_RELEASE_DATE = "2023-12-07";
|
||||
/**
|
||||
* Version 1.20.4 - the decorated pot update
|
||||
*/
|
||||
public static final MinecraftVersion v1_20_4 = new MinecraftVersion("1.20.4");
|
||||
|
||||
/**
|
||||
* Version 1.20.2 - the update that added the configuration protocol phase.
|
||||
*/
|
||||
public static final MinecraftVersion CONFIG_PHASE_PROTOCOL_UPDATE = new MinecraftVersion("1.20.2");
|
||||
/**
|
||||
* Version 1.20 - the trails and tails update
|
||||
*/
|
||||
public static final MinecraftVersion TRAILS_AND_TAILS = new MinecraftVersion("1.20");
|
||||
|
||||
/**
|
||||
* Version 1.19.4 - the rest of the feature preview
|
||||
*/
|
||||
public static final MinecraftVersion FEATURE_PREVIEW_2 = new MinecraftVersion("1.19.4");
|
||||
|
||||
/**
|
||||
* Version 1.19.3 - introducing feature preview
|
||||
*/
|
||||
public static final MinecraftVersion FEATURE_PREVIEW_UPDATE = new MinecraftVersion("1.19.3");
|
||||
/**
|
||||
* Version 1.19 - the wild update
|
||||
*/
|
||||
public static final MinecraftVersion WILD_UPDATE = new MinecraftVersion("1.19");
|
||||
/**
|
||||
* Version 1.18 - caves and cliffs part 2
|
||||
*/
|
||||
public static final MinecraftVersion CAVES_CLIFFS_2 = new MinecraftVersion("1.18");
|
||||
/**
|
||||
* Version 1.17 - caves and cliffs part 1
|
||||
*/
|
||||
public static final MinecraftVersion CAVES_CLIFFS_1 = new MinecraftVersion("1.17");
|
||||
/**
|
||||
* Version 1.16.4
|
||||
*/
|
||||
public static final MinecraftVersion NETHER_UPDATE_4 = new MinecraftVersion("1.16.4");
|
||||
/**
|
||||
* Version 1.16.2 - breaking change to the nether update
|
||||
*/
|
||||
public static final MinecraftVersion NETHER_UPDATE_2 = new MinecraftVersion("1.16.2");
|
||||
/**
|
||||
* Version 1.16.0 - the nether update
|
||||
*/
|
||||
public static final MinecraftVersion NETHER_UPDATE = new MinecraftVersion("1.16");
|
||||
/**
|
||||
* Version 1.15 - the bee update
|
||||
*/
|
||||
public static final MinecraftVersion BEE_UPDATE = new MinecraftVersion("1.15");
|
||||
/**
|
||||
* Version 1.14 - village and pillage update.
|
||||
*/
|
||||
public static final MinecraftVersion VILLAGE_UPDATE = new MinecraftVersion("1.14");
|
||||
/**
|
||||
* Version 1.13 - update aquatic.
|
||||
*/
|
||||
public static final MinecraftVersion AQUATIC_UPDATE = new MinecraftVersion("1.13");
|
||||
/**
|
||||
* Version 1.12 - the world of color update.
|
||||
*/
|
||||
public static final MinecraftVersion COLOR_UPDATE = new MinecraftVersion("1.12");
|
||||
/**
|
||||
* Version 1.11 - the exploration update.
|
||||
*/
|
||||
public static final MinecraftVersion EXPLORATION_UPDATE = new MinecraftVersion("1.11");
|
||||
/**
|
||||
* Version 1.10 - the frostburn update.
|
||||
*/
|
||||
public static final MinecraftVersion FROSTBURN_UPDATE = new MinecraftVersion("1.10");
|
||||
/**
|
||||
* Version 1.9 - the combat update.
|
||||
*/
|
||||
public static final MinecraftVersion COMBAT_UPDATE = new MinecraftVersion("1.9");
|
||||
/**
|
||||
* Version 1.8 - the "bountiful" update.
|
||||
*/
|
||||
public static final MinecraftVersion BOUNTIFUL_UPDATE = new MinecraftVersion("1.8");
|
||||
/**
|
||||
* Version 1.7.8 - the update that changed the skin format (and distribution - R.I.P. player disguise)
|
||||
*/
|
||||
public static final MinecraftVersion SKIN_UPDATE = new MinecraftVersion("1.7.8");
|
||||
/**
|
||||
* Version 1.7.2 - the update that changed the world.
|
||||
*/
|
||||
public static final MinecraftVersion WORLD_UPDATE = new MinecraftVersion("1.7.2");
|
||||
/**
|
||||
* Version 1.6.1 - the horse update.
|
||||
*/
|
||||
public static final MinecraftVersion HORSE_UPDATE = new MinecraftVersion("1.6.1");
|
||||
/**
|
||||
* Version 1.5.0 - the redstone update.
|
||||
*/
|
||||
public static final MinecraftVersion REDSTONE_UPDATE = new MinecraftVersion("1.5.0");
|
||||
/**
|
||||
* Version 1.4.2 - the scary update (Wither Boss).
|
||||
*/
|
||||
public static final MinecraftVersion SCARY_UPDATE = new MinecraftVersion("1.4.2");
|
||||
|
||||
/**
|
||||
* The latest release version of minecraft.
|
||||
*/
|
||||
public static final MinecraftVersion LATEST = v1_20_4;
|
||||
|
||||
// used when serializing
|
||||
private static final long serialVersionUID = -8695133558996459770L;
|
||||
|
||||
/**
|
||||
* Regular expression used to parse version strings.
|
||||
*/
|
||||
private static final Pattern VERSION_PATTERN = Pattern.compile(".*\\(.*MC.\\s*([a-zA-z0-9\\-.]+).*");
|
||||
|
||||
/**
|
||||
* The current version of minecraft, lazy initialized by MinecraftVersion.currentVersion()
|
||||
*/
|
||||
private static MinecraftVersion currentVersion;
|
||||
|
||||
private final int major;
|
||||
private final int minor;
|
||||
private final int build;
|
||||
// The development stage
|
||||
private final String development;
|
||||
|
||||
// Snapshot?
|
||||
private final SnapshotVersion snapshot;
|
||||
private volatile Boolean atCurrentOrAbove;
|
||||
|
||||
/**
|
||||
* Determine the current Minecraft version.
|
||||
*
|
||||
* @param server - the Bukkit server that will be used to examine the MC version.
|
||||
*/
|
||||
public MinecraftVersion(Server server) {
|
||||
this(extractVersion(server.getVersion()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a version object from the format major.minor.build, or the snapshot format.
|
||||
*
|
||||
* @param versionOnly - the version in text form.
|
||||
*/
|
||||
public MinecraftVersion(String versionOnly) {
|
||||
this(versionOnly, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a version format from the standard release version or the snapshot verison.
|
||||
*
|
||||
* @param versionOnly - the version.
|
||||
* @param parseSnapshot - TRUE to parse the snapshot, FALSE otherwise.
|
||||
*/
|
||||
private MinecraftVersion(String versionOnly, boolean parseSnapshot) {
|
||||
String[] section = versionOnly.split("-");
|
||||
SnapshotVersion snapshot = null;
|
||||
int[] numbers = new int[3];
|
||||
|
||||
try {
|
||||
numbers = this.parseVersion(section[0]);
|
||||
} catch (NumberFormatException cause) {
|
||||
// Skip snapshot parsing
|
||||
if (!parseSnapshot) {
|
||||
throw cause;
|
||||
}
|
||||
|
||||
try {
|
||||
// Determine if the snapshot is newer than the current release version
|
||||
snapshot = new SnapshotVersion(section[0]);
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
|
||||
|
||||
MinecraftVersion latest = new MinecraftVersion(MAXIMUM_MINECRAFT_VERSION, false);
|
||||
boolean newer = snapshot.getSnapshotDate().compareTo(
|
||||
format.parse(MINECRAFT_LAST_RELEASE_DATE)) > 0;
|
||||
|
||||
numbers[0] = latest.getMajor();
|
||||
numbers[1] = latest.getMinor() + (newer ? 1 : -1);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Cannot parse " + section[0], e);
|
||||
}
|
||||
}
|
||||
|
||||
this.major = numbers[0];
|
||||
this.minor = numbers[1];
|
||||
this.build = numbers[2];
|
||||
this.development = section.length > 1 ? section[1] : (snapshot != null ? "snapshot" : null);
|
||||
this.snapshot = snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a version object directly.
|
||||
*
|
||||
* @param major - major version number.
|
||||
* @param minor - minor version number.
|
||||
* @param build - build version number.
|
||||
*/
|
||||
public MinecraftVersion(int major, int minor, int build) {
|
||||
this(major, minor, build, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a version object directly.
|
||||
*
|
||||
* @param major - major version number.
|
||||
* @param minor - minor version number.
|
||||
* @param build - build version number.
|
||||
* @param development - development stage.
|
||||
*/
|
||||
public MinecraftVersion(int major, int minor, int build, String development) {
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.build = build;
|
||||
this.development = development;
|
||||
this.snapshot = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the Minecraft version from CraftBukkit itself.
|
||||
*
|
||||
* @param text - the server version in text form.
|
||||
* @return The underlying MC version.
|
||||
* @throws IllegalStateException If we could not parse the version string.
|
||||
*/
|
||||
public static String extractVersion(String text) {
|
||||
Matcher version = VERSION_PATTERN.matcher(text);
|
||||
|
||||
if (version.matches() && (version.group(1) != null)) {
|
||||
return version.group(1);
|
||||
} else {
|
||||
throw new IllegalStateException("Cannot parse version String '" + text + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given server version into a Minecraft version.
|
||||
*
|
||||
* @param serverVersion - the server version.
|
||||
* @return The resulting Minecraft version.
|
||||
*/
|
||||
public static MinecraftVersion fromServerVersion(String serverVersion) {
|
||||
return new MinecraftVersion(extractVersion(serverVersion));
|
||||
}
|
||||
|
||||
public static MinecraftVersion getCurrentVersion() {
|
||||
if (currentVersion == null) {
|
||||
currentVersion = fromServerVersion(Bukkit.getVersion());
|
||||
}
|
||||
|
||||
return currentVersion;
|
||||
}
|
||||
|
||||
public static void setCurrentVersion(MinecraftVersion version) {
|
||||
currentVersion = version;
|
||||
}
|
||||
|
||||
private static boolean atOrAbove(MinecraftVersion version) {
|
||||
return getCurrentVersion().isAtLeast(version);
|
||||
}
|
||||
|
||||
private int[] parseVersion(String version) {
|
||||
String[] elements = version.split("\\.");
|
||||
int[] numbers = new int[3];
|
||||
|
||||
// Make sure it's even a valid version
|
||||
if (elements.length < 1) {
|
||||
throw new IllegalStateException("Corrupt MC version: " + version);
|
||||
}
|
||||
|
||||
// The String 1 or 1.2 is interpreted as 1.0.0 and 1.2.0 respectively.
|
||||
for (int i = 0; i < Math.min(numbers.length, elements.length); i++) {
|
||||
numbers[i] = Integer.parseInt(elements[i].trim());
|
||||
}
|
||||
return numbers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Major version number
|
||||
*
|
||||
* @return Current major version number.
|
||||
*/
|
||||
public int getMajor() {
|
||||
return this.major;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minor version number
|
||||
*
|
||||
* @return Current minor version number.
|
||||
*/
|
||||
public int getMinor() {
|
||||
return this.minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build version number
|
||||
*
|
||||
* @return Current build version number.
|
||||
*/
|
||||
public int getBuild() {
|
||||
return this.build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the development stage.
|
||||
*
|
||||
* @return Development stage, or NULL if this is a release.
|
||||
*/
|
||||
public String getDevelopmentStage() {
|
||||
return this.development;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the snapshot version, or NULL if this is a release.
|
||||
*
|
||||
* @return The snapshot version.
|
||||
*/
|
||||
public SnapshotVersion getSnapshot() {
|
||||
return this.snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this version is a snapshot.
|
||||
*
|
||||
* @return The snapshot version.
|
||||
*/
|
||||
public boolean isSnapshot() {
|
||||
return this.snapshot != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this version is at or above the current version the server is running.
|
||||
*
|
||||
* @return true if this version is equal or newer than the server version, false otherwise.
|
||||
*/
|
||||
public boolean atOrAbove() {
|
||||
if (this.atCurrentOrAbove == null) {
|
||||
this.atCurrentOrAbove = atOrAbove(this);
|
||||
}
|
||||
|
||||
return this.atCurrentOrAbove;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the version String (major.minor.build) only.
|
||||
*
|
||||
* @return A normal version string.
|
||||
*/
|
||||
public String getVersion() {
|
||||
if (this.getDevelopmentStage() == null) {
|
||||
return String.format("%s.%s.%s", this.getMajor(), this.getMinor(), this.getBuild());
|
||||
} else {
|
||||
return String.format("%s.%s.%s-%s%s", this.getMajor(), this.getMinor(), this.getBuild(),
|
||||
this.getDevelopmentStage(), this.isSnapshot() ? this.snapshot : "");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(MinecraftVersion o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ComparisonChain.start()
|
||||
.compare(this.getMajor(), o.getMajor())
|
||||
.compare(this.getMinor(), o.getMinor())
|
||||
.compare(this.getBuild(), o.getBuild())
|
||||
.compare(this.getDevelopmentStage(), o.getDevelopmentStage(), Ordering.natural().nullsLast())
|
||||
.compare(this.getSnapshot(), o.getSnapshot(), Ordering.natural().nullsFirst())
|
||||
.result();
|
||||
}
|
||||
|
||||
public boolean isAtLeast(MinecraftVersion other) {
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.compareTo(other) >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof MinecraftVersion) {
|
||||
MinecraftVersion other = (MinecraftVersion) obj;
|
||||
|
||||
return (this.getMajor() == other.getMajor()) &&
|
||||
(this.getMinor() == other.getMinor()) &&
|
||||
(this.getBuild() == other.getBuild()) &&
|
||||
Objects.equals(this.getDevelopmentStage(), other.getDevelopmentStage());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.getMajor(), this.getMinor(), this.getBuild());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// Convert to a String that we can parse back again
|
||||
return String.format("(MC: %s)", this.getVersion());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.github.joelgodofwar.mmh.util;
|
||||
import java.io.Serializable;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
|
||||
/**
|
||||
* Used to parse a snapshot version.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class SnapshotVersion implements Comparable<SnapshotVersion>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2778655372579322310L;
|
||||
private static final Pattern SNAPSHOT_PATTERN = Pattern.compile("(\\d{2}w\\d{2})([a-z])");
|
||||
|
||||
private final Date snapshotDate;
|
||||
private final int snapshotWeekVersion;
|
||||
|
||||
private transient String rawString;
|
||||
|
||||
public SnapshotVersion(String version) {
|
||||
Matcher matcher = SNAPSHOT_PATTERN.matcher(version.trim());
|
||||
|
||||
if (matcher.matches()) {
|
||||
try {
|
||||
this.snapshotDate = getDateFormat().parse(matcher.group(1));
|
||||
this.snapshotWeekVersion = matcher.group(2).charAt(0) - 'a';
|
||||
this.rawString = version;
|
||||
} catch (ParseException e) {
|
||||
throw new IllegalArgumentException("Date implied by snapshot version is invalid.", e);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Cannot parse " + version + " as a snapshot version.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the snapshot date parser.
|
||||
* <p>
|
||||
* We have to create a new instance of SimpleDateFormat every time as it is not thread safe.
|
||||
*
|
||||
* @return The date formatter.
|
||||
*/
|
||||
private static SimpleDateFormat getDateFormat() {
|
||||
SimpleDateFormat format = new SimpleDateFormat("yy'w'ww", Locale.US);
|
||||
format.setLenient(false);
|
||||
return format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the snapshot version within a week, starting at zero.
|
||||
*
|
||||
* @return The weekly version
|
||||
*/
|
||||
public int getSnapshotWeekVersion() {
|
||||
return this.snapshotWeekVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the week this snapshot was released.
|
||||
*
|
||||
* @return The week.
|
||||
*/
|
||||
public Date getSnapshotDate() {
|
||||
return this.snapshotDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the raw snapshot string (yy'w'ww[a-z]).
|
||||
*
|
||||
* @return The snapshot string.
|
||||
*/
|
||||
public String getSnapshotString() {
|
||||
if (this.rawString == null) {
|
||||
// It's essential that we use the same locale
|
||||
Calendar current = Calendar.getInstance(Locale.US);
|
||||
current.setTime(this.snapshotDate);
|
||||
this.rawString = String.format("%02dw%02d%s",
|
||||
current.get(Calendar.YEAR) % 100,
|
||||
current.get(Calendar.WEEK_OF_YEAR),
|
||||
(char) ('a' + this.snapshotWeekVersion));
|
||||
}
|
||||
return this.rawString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(SnapshotVersion o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ComparisonChain.start()
|
||||
.compare(this.snapshotDate, o.getSnapshotDate())
|
||||
.compare(this.snapshotWeekVersion, o.getSnapshotWeekVersion())
|
||||
.result();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof SnapshotVersion) {
|
||||
SnapshotVersion other = (SnapshotVersion) obj;
|
||||
return Objects.equals(this.snapshotDate, other.getSnapshotDate())
|
||||
&& (this.snapshotWeekVersion == other.getSnapshotWeekVersion());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.snapshotDate, this.snapshotWeekVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getSnapshotString();
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,13 @@ package com.github.joelgodofwar.mmh.util;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
public class StrUtils {
|
||||
/** StringRight */
|
||||
/**
|
||||
* Returns the rightmost characters of a string up to the specified length.
|
||||
*
|
||||
* @param input The input string.
|
||||
* @param chars The number of characters to retrieve from the right.
|
||||
* @return The rightmost characters of the input string, or the full string if its length is less than or equal to the specified length.
|
||||
*/
|
||||
public static String Right(String input, int chars){
|
||||
if (input.length() > chars){
|
||||
//System.out.println("Right input=" + input);
|
||||
@@ -14,7 +20,13 @@ public class StrUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** StringLeft */
|
||||
/**
|
||||
* Returns the leftmost characters of a string up to the specified length.
|
||||
*
|
||||
* @param input The input string.
|
||||
* @param chars The number of characters to retrieve from the left.
|
||||
* @return The leftmost characters of the input string, or the full string if its length is less than or equal to the specified length.
|
||||
*/
|
||||
public static String Left(String input, int chars){
|
||||
if (input.length() > chars){
|
||||
//System.out.println("Left input=" + input);
|
||||
@@ -26,7 +38,13 @@ public class StrUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* Checks if a string contains a specified substring, ignoring case.
|
||||
*
|
||||
* @param string The input string to search within (comma-separated values).
|
||||
* @param string2 The substring to check for.
|
||||
* @return True if the substring is found in the input string; otherwise, false.
|
||||
*/
|
||||
public static boolean stringContains(String string, String string2){
|
||||
String[] string3 = string.toUpperCase().split(", ");
|
||||
for(int i = 0; i < string3.length; i++){
|
||||
@@ -37,6 +55,13 @@ public class StrUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two strings for equality after removing color codes.
|
||||
*
|
||||
* @param string1 The first string to compare.
|
||||
* @param string2 The second string to compare.
|
||||
* @return True if the strings are equal (ignoring color codes); otherwise, false.
|
||||
*/
|
||||
public static boolean stringEquals(String string1, String string2) {
|
||||
//string1 = ChatColor.stripColor(string1);
|
||||
//string2 = ChatColor.stripColor(string2);
|
||||
@@ -46,6 +71,13 @@ public class StrUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the first character of a string to uppercase and the remaining characters to lowercase,
|
||||
* creating a title case format.
|
||||
*
|
||||
* @param input The input string to convert to title case.
|
||||
* @return The input string in Title Case.
|
||||
*/
|
||||
public static String toTitleCase(String input) {
|
||||
if ((input == null) || input.isEmpty()) {
|
||||
return input;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.github.joelgodofwar.mmh.util;
|
||||
|
||||
import org.apache.commons.lang.math.NumberUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@@ -8,15 +9,15 @@ import org.bukkit.entity.Player;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
|
||||
public class Utils {
|
||||
|
||||
|
||||
public static void sendJson(CommandSender player, String string){
|
||||
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), "tellraw \"" + player.getName() + "\" " + string);
|
||||
}
|
||||
|
||||
|
||||
public static void sendJson(Player player, String string){
|
||||
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), "tellraw \"" + player.getName() + "\" " + string);
|
||||
}
|
||||
|
||||
|
||||
public String parsePAPI(String string) {
|
||||
if(Bukkit.getServer().getPluginManager().getPlugin("PlaceholderAPI") != null){
|
||||
return PlaceholderAPI.setPlaceholders(null, string);
|
||||
@@ -24,7 +25,7 @@ public class Utils {
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String parsePAPI(Player player, String string) {
|
||||
if(Bukkit.getServer().getPluginManager().getPlugin("PlaceholderAPI") != null){
|
||||
return PlaceholderAPI.setPlaceholders(player, string);
|
||||
@@ -32,7 +33,7 @@ public class Utils {
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String parsePAPI(OfflinePlayer player, String string) {
|
||||
if(Bukkit.getServer().getPluginManager().getPlugin("PlaceholderAPI") != null){
|
||||
return PlaceholderAPI.setPlaceholders(player, string);
|
||||
@@ -40,5 +41,75 @@ public class Utils {
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the server version is supported based on minimum Minecraft version and build number.
|
||||
*
|
||||
* @param minMCVersion Minimum Minecraft version in the format "Major.Minor.BugFix.Build" (e.g., "1.20.2.3936").
|
||||
* @return True if the server version is not supported; otherwise, false.
|
||||
*/
|
||||
public static boolean isSupportedVersion(String minMCVersion) {
|
||||
// 3936-Spigot-dba3cdc-5a2d905 (MC: 1.20.2)
|
||||
// 0 1 2
|
||||
//String[] minVersion = minMCVersion.split("\\.");
|
||||
Version minVersion = new Version(minMCVersion);
|
||||
|
||||
String serverVersion = Bukkit.getVersion(); // Get the server version string
|
||||
String[] versionParts = serverVersion.split(" "); // Split by space to get the MC version and build number
|
||||
String daVersion = versionParts[2].replace(")", ".").concat(serverVersion.split("-")[0]);
|
||||
/**System.out.println("Bukkit.getVersion()=" + Bukkit.getVersion());
|
||||
System.out.println("versionParts.length=" + versionParts.length);
|
||||
System.out.println("versionParts.0=" + versionParts[0]);
|
||||
System.out.println("versionParts.1=" + versionParts[1]);
|
||||
System.out.println("versionParts.1=" + versionParts[2]);//*/
|
||||
Version checkVersion = new Version(daVersion);
|
||||
|
||||
if(minVersion.Major() > checkVersion.Major()){return true;}
|
||||
if(minVersion.Major() == checkVersion.Major()){/** same do nothing */}
|
||||
if(minVersion.Minor() > checkVersion.Minor()){return true;}
|
||||
else if(minVersion.Minor() == checkVersion.Minor()){/** same do nothing */}
|
||||
if(minVersion.Patch() > checkVersion.Patch()){return true;}
|
||||
else if(minVersion.Patch() == checkVersion.Patch()){/** same do nothing */}
|
||||
if(minVersion.Build() > checkVersion.Build()){return true;}
|
||||
else if(minVersion.Build() == checkVersion.Build()){/** same do nothing */}
|
||||
|
||||
return true; // Server version is not supported
|
||||
}
|
||||
|
||||
public static class Version{
|
||||
private int Major; // 1
|
||||
private int Minor; // 16
|
||||
private int Patch; // 1
|
||||
private int Build; // ?
|
||||
private boolean isDev = false;
|
||||
private String[] string2 = {"0","0","0","0"};
|
||||
public Version(String string){
|
||||
//System.out.println("string=" + string);
|
||||
string2 = string.split("\\.");
|
||||
/**for (String a : string2) {
|
||||
System.out.println(a);
|
||||
System.out.println("string2=" + string2.toString());
|
||||
System.out.println("string2.length=" + string2.length);
|
||||
}//*/
|
||||
this.Major = NumberUtils.toInt(string2[0]);
|
||||
this.Minor = NumberUtils.toInt(string2[1]);
|
||||
this.Patch = NumberUtils.toInt(string2[2]);
|
||||
if(string2.length >= 4){
|
||||
if(string2[3].toUpperCase().contains("D")){
|
||||
isDev = true;
|
||||
string2[3] = string2[3].toUpperCase().replace("D", "");
|
||||
}
|
||||
this.Build = NumberUtils.toInt(string2[3]);
|
||||
}else{
|
||||
this.Build = 0;
|
||||
}
|
||||
}
|
||||
public int Major(){return Major;}
|
||||
public int Minor(){return Minor;}
|
||||
public int Patch(){return Patch;}
|
||||
public int Build(){return Build;}
|
||||
public boolean isDev(){return isDev;}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package com.github.joelgodofwar.mmh.util;
|
||||
|
||||
import com.github.joelgodofwar.mmh.MoreMobHeads;
|
||||
|
||||
/**
|
||||
* Utility class for verifying and retrieving values from a FileConfiguration.
|
||||
*/
|
||||
public class VerifyConfig {
|
||||
MoreMobHeads mmh;
|
||||
|
||||
/**
|
||||
* Constructs a VerifyConfig object with the given FileConfiguration.
|
||||
*
|
||||
* @param config The FileConfiguration to be verified.
|
||||
*/
|
||||
public VerifyConfig(final MoreMobHeads plugin) {
|
||||
this.mmh = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a string value from the configuration for the specified path.
|
||||
* If the value is null, the specified defaultValue is returned.
|
||||
*
|
||||
* @param path The path to the configuration value.
|
||||
* @param defaultValue The default value to be returned if the specified path is null.
|
||||
* @return The retrieved string value or the defaultValue if null.
|
||||
*/
|
||||
public String getString(String path, String defaultValue ) {
|
||||
try {
|
||||
String stringValue = mmh.getConfig().getString(path, null);
|
||||
if (stringValue == null) {
|
||||
throw new NullPointerException("Could not read value of: " + path);
|
||||
}
|
||||
return stringValue;
|
||||
}catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a boolean value from the configuration for the specified path.
|
||||
* If the value is null, the specified defaultValue is returned.
|
||||
*
|
||||
* @param path The path to the configuration value.
|
||||
* @param defaultValue The default value to be returned if the specified path is null.
|
||||
* @return The retrieved boolean value or the defaultValue if null.
|
||||
*/
|
||||
public boolean getBoolean(String path, boolean defaultValue ) {
|
||||
try {
|
||||
String stringValue = mmh.getConfig().getString(path, null);
|
||||
if (stringValue == null) {
|
||||
throw new NullPointerException("Could not read value of: " + path);
|
||||
}
|
||||
return Boolean.parseBoolean(stringValue);
|
||||
}catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an integer value from the configuration for the specified path.
|
||||
* If the value is null, the specified defaultValue is returned.
|
||||
*
|
||||
* @param path The path to the configuration value.
|
||||
* @param defaultValue The default value to be returned if the specified path is null.
|
||||
* @return The retrieved integer value or the defaultValue if null.
|
||||
*/
|
||||
public int getInt(String path, int defaultValue ) {
|
||||
try {
|
||||
String stringValue = mmh.getConfig().getString(path, null);
|
||||
if (stringValue == null) {
|
||||
throw new NullPointerException("Could not read value of: " + path);
|
||||
}
|
||||
return Integer.parseInt(stringValue);
|
||||
}catch (NullPointerException | NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public boolean checkString(String path){
|
||||
try {
|
||||
String stringValue = mmh.getConfig().getString(path, null);
|
||||
if(stringValue != null) {
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}catch(Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void verifyValues() {
|
||||
mmh.LOGGER.log("plugin_settings.auto_update_check " + getBoolean("plugin_settings.auto_update_check", true));
|
||||
mmh.LOGGER.log("plugin_settings.debug " + getBoolean("plugin_settings.debug", false));
|
||||
mmh.LOGGER.log("plugin_settings.lang " + getString("plugin_settings.lang", "en_US"));
|
||||
mmh.LOGGER.log("global_settings.console.colorful_console " + getBoolean("global_settings.console.colorful_console", true));
|
||||
mmh.LOGGER.log("global_settings.console.silent_console " + getBoolean("global_settings.console.silent_console", true));
|
||||
mmh.LOGGER.log("global_settings.console.longpluginname " + getBoolean("global_settings.console.longpluginname", true));
|
||||
mmh.LOGGER.log("global_settings.world.whitelist " + getString("global_settings.world.whitelist", ""));
|
||||
mmh.LOGGER.log("global_settings.world.blacklist " + getString("global_settings.world.blacklist", ""));
|
||||
mmh.LOGGER.log("global_settings.event.piston_extend " + getBoolean("global_settings.event.piston_extend", true));
|
||||
mmh.LOGGER.log("head_settings.apply_looting " + getBoolean("head_settings.apply_looting", true));
|
||||
mmh.LOGGER.log("head_settings.lore.show_killer " + getBoolean("head_settings.lore.show_killer", true));
|
||||
mmh.LOGGER.log("head_settings.lore.show_plugin_name " + getBoolean("head_settings.lore.show_plugin_name", true));
|
||||
mmh.LOGGER.log("head_settings.player_heads.announce_kill.enabled" + getBoolean("head_settings.player_heads.announce_kill.enabled", false));
|
||||
mmh.LOGGER.log("head_settings.player_heads.announce_kill.displayname " + getBoolean("head_settings.player_heads.announce_kill.displayname", true));
|
||||
mmh.LOGGER.log("head_settings.player_heads.whitelist.enforce " + getBoolean("head_settings.player_heads.whitelist.enforce", true));
|
||||
mmh.LOGGER.log("head_settings.player_heads.whitelist.player_head_whitelist " + getString("head_settings.player_heads.whitelist.player_head_whitelist", ""));
|
||||
mmh.LOGGER.log("head_settings.player_heads.blacklist.enforce " + getBoolean("head_settings.player_heads.blacklist.enforce", true));
|
||||
mmh.LOGGER.log("head_settings.player_heads.blacklist.player_head_blacklist " + getString("head_settings.player_heads.blacklist.player_head_blacklist", ""));
|
||||
mmh.LOGGER.log("head_settings.mob_heads.announce_kill.enabled " + getBoolean("head_settings.mob_heads.announce_kill.enabled", false));
|
||||
mmh.LOGGER.log("head_settings.mob_heads.announce_kill.displayname " + getBoolean("head_settings.mob_heads.announce_kill.displayname", true));
|
||||
mmh.LOGGER.log("head_settings.mob_heads.whitelist " + getString("head_settings.mob_heads.whitelist", ""));
|
||||
mmh.LOGGER.log("head_settings.mob_heads.blacklist " + getString("head_settings.mob_heads.blacklist", ""));
|
||||
mmh.LOGGER.log("head_settings.mob_heads.nametag " + getBoolean("head_settings.mob_heads.nametag", false));
|
||||
mmh.LOGGER.log("head_settings.mob_heads.vanilla_heads.creepers " + getBoolean("head_settings.mob_heads.vanilla_heads.creepers", true));
|
||||
mmh.LOGGER.log("head_settings.mob_heads.vanilla_heads.ender_dragon " + getBoolean("head_settings.mob_heads.vanilla_heads.ender_dragon", true));
|
||||
mmh.LOGGER.log("head_settings.mob_heads.vanilla_heads.piglin " + getBoolean("head_settings.mob_heads.vanilla_heads.piglin", true));
|
||||
mmh.LOGGER.log("head_settings.mob_heads.vanilla_heads.skeleton " + getBoolean("head_settings.mob_heads.vanilla_heads.skeleton", true));
|
||||
mmh.LOGGER.log("head_settings.mob_heads.vanilla_heads.wither_skeleto " + getBoolean("head_settings.mob_heads.vanilla_heads.wither_skeleton", true));
|
||||
mmh.LOGGER.log("head_settings.mob_heads.vanilla_heads.zombie " + getBoolean("head_settings.mob_heads.vanilla_heads.zombie", true));
|
||||
mmh.LOGGER.log("wandering_trades.custom_wandering_trader " + getBoolean("wandering_trades.custom_wandering_trader", true));
|
||||
mmh.LOGGER.log("wandering_trades.keep_default_trades " + getBoolean("wandering_trades.keep_default_trades", true));
|
||||
mmh.LOGGER.log("wandering_trades.player_heads.enabled " + getBoolean("wandering_trades.player_heads.enabled", true));
|
||||
mmh.LOGGER.log("wandering_trades.player_heads.min " + getInt("wandering_trades.player_heads.min", 0));
|
||||
mmh.LOGGER.log("wandering_trades.player_heads.max " + getInt("wandering_trades.player_heads.max", 5));
|
||||
mmh.LOGGER.log("wandering_trades.block_heads.enabled " + getBoolean("wandering_trades.block_heads.enabled", true));
|
||||
mmh.LOGGER.log("wandering_trades.block_heads.pre_116.min" + getInt("wandering_trades.block_heads.pre_116.min", 0));
|
||||
mmh.LOGGER.log("wandering_trades.block_heads.pre_116.max " + getInt("wandering_trades.block_heads.pre_116.max", 5));
|
||||
mmh.LOGGER.log("wandering_trades.block_heads.is_116.min" + getInt("wandering_trades.block_heads.is_116.min", 0));
|
||||
mmh.LOGGER.log("wandering_trades.block_heads.is_116.max " + getInt("wandering_trades.block_heads.is_116.max", 5));
|
||||
mmh.LOGGER.log("wandering_trades.block_heads.is_117.min " + getInt("wandering_trades.block_heads.is_117.min", 0));
|
||||
mmh.LOGGER.log("wandering_trades.block_heads.is_117.max " + getInt("wandering_trades.block_heads.is_117.max", 5));
|
||||
mmh.LOGGER.log("wandering_trades.custom_trades.enabled " + getBoolean("wandering_trades.custom_trades.enabled", true));
|
||||
mmh.LOGGER.log("wandering_trades.custom_trades.min " + getInt("wandering_trades.custom_trades.min", 0));
|
||||
mmh.LOGGER.log("wandering_trades.custom_trades.max " + getInt("wandering_trades.custom_trades.max", 5));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,13 +4,15 @@ import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
//import java.util.Scanner;
|
||||
//import java.io.IOException;
|
||||
//import java.io.InputStream;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
@@ -18,135 +20,135 @@ import org.w3c.dom.NodeList;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class VersionChecker {
|
||||
private String pluginName;
|
||||
private String pluginName;
|
||||
private JavaPlugin plugin;
|
||||
private int projectID;
|
||||
private String currentVersion;
|
||||
private String githubURL; // = "https://github.com/JoelGodOfwar/MoreMobHeads/raw/master/versioncheck/1.15/versions.xml";
|
||||
private int projectID;
|
||||
private String currentVersion;
|
||||
private String githubURL; // = "https://github.com/JoelGodOfwar/MoreMobHeads/raw/master/versioncheck/1.15/versions.xml";
|
||||
String versionType;
|
||||
private List<String> releaseList = new ArrayList<>();
|
||||
private List<String> developerList = new ArrayList<>();
|
||||
private String recommendedVersion = "uptodate";
|
||||
private List<String> developerList = new ArrayList<>();
|
||||
private String recommendedVersion = "uptodate";
|
||||
|
||||
public VersionChecker(JavaPlugin plugin, int projectID, String githubURL) {
|
||||
this.plugin = plugin;
|
||||
this.projectID = projectID;
|
||||
this.currentVersion = plugin.getDescription().getVersion();
|
||||
this.githubURL = githubURL;
|
||||
}
|
||||
|
||||
public VersionChecker(String plugin, int projectID, String githubURL) {
|
||||
this.currentVersion = plugin;
|
||||
this.projectID = projectID;
|
||||
this.githubURL = githubURL;
|
||||
}
|
||||
|
||||
public String getReleaseUrl() {return "https://spigotmc.org/resources/" + projectID;}
|
||||
|
||||
public boolean checkForUpdates() throws Exception {
|
||||
URL url = new URL(githubURL);
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
URLConnection connection = url.openConnection();
|
||||
connection.setUseCaches(false);
|
||||
connection.setRequestProperty("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
Document doc = db.parse(connection.getInputStream());
|
||||
doc.getDocumentElement().normalize();
|
||||
NodeList releaseNodes = doc.getElementsByTagName("release");
|
||||
for (int i = 0; i < releaseNodes.getLength(); i++) {
|
||||
Node node = releaseNodes.item(i);
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
Element element = (Element) node;
|
||||
releaseList.add(element.getElementsByTagName("version").item(0).getTextContent().replace("<version>", "").replace("</version>", ""));
|
||||
releaseList.add(element.getElementsByTagName("notes").item(0).getTextContent().replace("<notes>", "").replace("</notes>", ""));
|
||||
releaseList.add(element.getElementsByTagName("link").item(0).getTextContent().replace("<link>", "").replace("</link>", ""));
|
||||
}
|
||||
}
|
||||
NodeList developerNodes = doc.getElementsByTagName("developer");
|
||||
for (int i = 0; i < developerNodes.getLength(); i++) {
|
||||
Node node = developerNodes.item(i);
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
Element element = (Element) node;
|
||||
developerList.add(element.getElementsByTagName("version").item(0).getTextContent().replace("<version>", "").replace("</version>", ""));
|
||||
developerList.add(element.getElementsByTagName("notes").item(0).getTextContent().replace("<notes>", "").replace("</notes>", ""));
|
||||
developerList.add(element.getElementsByTagName("link").item(0).getTextContent().replace("<link>", "").replace("</link>", ""));
|
||||
}
|
||||
}
|
||||
|
||||
if (connection != null) {
|
||||
connection.getInputStream().close();
|
||||
}
|
||||
String releaseVersion = releaseList.get(0);
|
||||
String developerVersion = developerList.get(0);
|
||||
Bukkit.getLogger().warning(Ansi.LIGHT_YELLOW + "currentVersion=" + currentVersion + Ansi.RESET);
|
||||
Bukkit.getLogger().warning(Ansi.LIGHT_YELLOW + "releaseVersion=" + releaseVersion + Ansi.RESET);
|
||||
Bukkit.getLogger().warning(Ansi.LIGHT_YELLOW + "developerVersion=" + developerVersion + Ansi.RESET);
|
||||
if (currentVersion.compareTo(releaseVersion) < 0) {
|
||||
recommendedVersion = "release";
|
||||
return true;
|
||||
} else if (currentVersion.equals(releaseVersion)) {
|
||||
recommendedVersion = "uptodate";
|
||||
return false;
|
||||
} else if (currentVersion.contains(".D")) {
|
||||
String[] splitCurrentVersion = currentVersion.split("\\.D");
|
||||
String currentReleaseVersion = splitCurrentVersion[0];
|
||||
String[] splitDeveloperVersion = developerVersion.split("\\.D");
|
||||
String developerReleaseVersion = splitDeveloperVersion[0];
|
||||
if (currentReleaseVersion.equals(releaseVersion) && developerReleaseVersion.compareTo(currentReleaseVersion) <= 0) {
|
||||
recommendedVersion = "release";
|
||||
return true;
|
||||
} else if (developerReleaseVersion.compareTo(releaseVersion) < 0 && developerReleaseVersion.equals(currentReleaseVersion)) {
|
||||
recommendedVersion = "You are Up To Date";
|
||||
return false;
|
||||
} else if (developerVersion.compareTo(currentVersion) > 0) {
|
||||
recommendedVersion = "developer";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public VersionChecker(JavaPlugin plugin, int projectID, String githubURL) {
|
||||
this.plugin = plugin;
|
||||
this.projectID = projectID;
|
||||
this.currentVersion = plugin.getDescription().getVersion();
|
||||
this.githubURL = githubURL;
|
||||
}
|
||||
|
||||
public VersionChecker(String plugin, int projectID, String githubURL) {
|
||||
this.currentVersion = plugin;
|
||||
this.projectID = projectID;
|
||||
this.githubURL = githubURL;
|
||||
}
|
||||
|
||||
public String getReleaseUrl() {return "https://dev.bukkit.org/projects/moremobheads2";}
|
||||
|
||||
public boolean checkForUpdates() throws Exception {
|
||||
URL url = new URL(githubURL);
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
URLConnection connection = url.openConnection();
|
||||
connection.setUseCaches(false);
|
||||
connection.setRequestProperty("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
Document doc = db.parse(connection.getInputStream());
|
||||
doc.getDocumentElement().normalize();
|
||||
NodeList releaseNodes = doc.getElementsByTagName("release");
|
||||
for (int i = 0; i < releaseNodes.getLength(); i++) {
|
||||
Node node = releaseNodes.item(i);
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
Element element = (Element) node;
|
||||
releaseList.add(element.getElementsByTagName("version").item(0).getTextContent().replace("<version>", "").replace("</version>", ""));
|
||||
releaseList.add(element.getElementsByTagName("notes").item(0).getTextContent().replace("<notes>", "").replace("</notes>", ""));
|
||||
releaseList.add(element.getElementsByTagName("link").item(0).getTextContent().replace("<link>", "").replace("</link>", ""));
|
||||
}
|
||||
}
|
||||
NodeList developerNodes = doc.getElementsByTagName("developer");
|
||||
for (int i = 0; i < developerNodes.getLength(); i++) {
|
||||
Node node = developerNodes.item(i);
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
Element element = (Element) node;
|
||||
developerList.add(element.getElementsByTagName("version").item(0).getTextContent().replace("<version>", "").replace("</version>", ""));
|
||||
developerList.add(element.getElementsByTagName("notes").item(0).getTextContent().replace("<notes>", "").replace("</notes>", ""));
|
||||
developerList.add(element.getElementsByTagName("link").item(0).getTextContent().replace("<link>", "").replace("</link>", ""));
|
||||
}
|
||||
}
|
||||
|
||||
if (connection != null) {
|
||||
connection.getInputStream().close();
|
||||
}
|
||||
String releaseVersion = releaseList.get(0);
|
||||
String developerVersion = developerList.get(0);
|
||||
Bukkit.getLogger().warning(Ansi.LIGHT_YELLOW + "currentVersion=" + currentVersion + Ansi.RESET);
|
||||
Bukkit.getLogger().warning(Ansi.LIGHT_YELLOW + "releaseVersion=" + releaseVersion + Ansi.RESET);
|
||||
Bukkit.getLogger().warning(Ansi.LIGHT_YELLOW + "developerVersion=" + developerVersion + Ansi.RESET);
|
||||
if (currentVersion.compareTo(releaseVersion) < 0) {
|
||||
recommendedVersion = "release";
|
||||
return true;
|
||||
} else if (currentVersion.equals(releaseVersion)) {
|
||||
recommendedVersion = "uptodate";
|
||||
return false;
|
||||
} else if (currentVersion.contains(".D")) {
|
||||
String[] splitCurrentVersion = currentVersion.split("\\.D");
|
||||
String currentReleaseVersion = splitCurrentVersion[0];
|
||||
String[] splitDeveloperVersion = developerVersion.split("\\.D");
|
||||
String developerReleaseVersion = splitDeveloperVersion[0];
|
||||
if (currentReleaseVersion.equals(releaseVersion) && (developerReleaseVersion.compareTo(currentReleaseVersion) <= 0)) {
|
||||
recommendedVersion = "release";
|
||||
return true;
|
||||
} else if ((developerReleaseVersion.compareTo(releaseVersion) < 0) && developerReleaseVersion.equals(currentReleaseVersion)) {
|
||||
recommendedVersion = "You are Up To Date";
|
||||
return false;
|
||||
} else if (developerVersion.compareTo(currentVersion) > 0) {
|
||||
recommendedVersion = "developer";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public List<String> getReleaseList() {
|
||||
return releaseList;
|
||||
}
|
||||
public List<String> getDeveloperList() {
|
||||
return developerList;
|
||||
}
|
||||
public String getRecommendedVersion() {
|
||||
return recommendedVersion;
|
||||
}
|
||||
public String oldVersion() {
|
||||
return currentVersion;
|
||||
}
|
||||
public String newVersion() {
|
||||
if(recommendedVersion.equalsIgnoreCase("release")) {
|
||||
return releaseList.get(0);
|
||||
}else if(recommendedVersion.equalsIgnoreCase("developer")) {
|
||||
return developerList.get(0);
|
||||
}else {
|
||||
return "UpToDate";
|
||||
}
|
||||
}
|
||||
public String newVersionNotes() {
|
||||
if (recommendedVersion.equalsIgnoreCase("release")) {
|
||||
return releaseList.get(1);
|
||||
} else if (recommendedVersion.equalsIgnoreCase("developer")) {
|
||||
return developerList.get(1);
|
||||
} else {
|
||||
return "UpToDate";
|
||||
}
|
||||
}
|
||||
public String getDownloadLink() {
|
||||
if (recommendedVersion.equalsIgnoreCase("release")) {
|
||||
return releaseList.get(2);//"https://www.spigotmc.org/resources/no-enderman-grief2.71236/history";
|
||||
} else if (recommendedVersion.equalsIgnoreCase("developer")) {
|
||||
return developerList.get(2);//"https://discord.com/channels/654087250665144321/654444482372173875";
|
||||
} else {
|
||||
return "UpToDate";
|
||||
}
|
||||
}
|
||||
|
||||
/**public boolean checkForUpdates2() {
|
||||
}
|
||||
public List<String> getReleaseList() {
|
||||
return releaseList;
|
||||
}
|
||||
public List<String> getDeveloperList() {
|
||||
return developerList;
|
||||
}
|
||||
public String getRecommendedVersion() {
|
||||
return recommendedVersion;
|
||||
}
|
||||
public String oldVersion() {
|
||||
return currentVersion;
|
||||
}
|
||||
public String newVersion() {
|
||||
if(recommendedVersion.equalsIgnoreCase("release")) {
|
||||
return releaseList.get(0);
|
||||
}else if(recommendedVersion.equalsIgnoreCase("developer")) {
|
||||
return developerList.get(0);
|
||||
}else {
|
||||
return "UpToDate";
|
||||
}
|
||||
}
|
||||
public String newVersionNotes() {
|
||||
if (recommendedVersion.equalsIgnoreCase("release")) {
|
||||
return releaseList.get(1);
|
||||
} else if (recommendedVersion.equalsIgnoreCase("developer")) {
|
||||
return developerList.get(1);
|
||||
} else {
|
||||
return "UpToDate";
|
||||
}
|
||||
}
|
||||
public String getDownloadLink() {
|
||||
if (recommendedVersion.equalsIgnoreCase("release")) {
|
||||
return releaseList.get(2);//"https://www.spigotmc.org/resources/no-enderman-grief2.71236/history";
|
||||
} else if (recommendedVersion.equalsIgnoreCase("developer")) {
|
||||
return developerList.get(2);//"https://discord.com/channels/654087250665144321/654444482372173875";
|
||||
} else {
|
||||
return "UpToDate";
|
||||
}
|
||||
}
|
||||
|
||||
/**public boolean checkForUpdates2() {
|
||||
if(currentVersion.contains(".D")){
|
||||
versionType = "developer";
|
||||
}else{
|
||||
@@ -176,7 +178,7 @@ public class VersionChecker {
|
||||
}
|
||||
}//*/
|
||||
|
||||
/**private String[] getLatestVersion(String versionType) {
|
||||
/**private String[] getLatestVersion(String versionType) {
|
||||
try {
|
||||
URL url = new URL(githubURL);
|
||||
InputStream stream = url.openStream();
|
||||
@@ -210,7 +212,7 @@ public class VersionChecker {
|
||||
}
|
||||
}//*/
|
||||
|
||||
/**public static void main(String[] args) {
|
||||
/**public static void main(String[] args) {
|
||||
//String pluginName = "MyPlugin";
|
||||
String currentVersion = "1.14_1.0.4";
|
||||
String githubURL = "https://github.com/JoelGodOfwar/NoEndermanGrief/raw/master/versions/1.14/versions.xml";
|
||||
|
||||
@@ -12,8 +12,6 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import jdk.internal.joptsimple.internal.Strings;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
@@ -25,99 +23,92 @@ import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.representer.Representer;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
|
||||
import jdk.internal.joptsimple.internal.Strings;
|
||||
|
||||
/*
|
||||
* @author: Aoife (Josh)
|
||||
* @date: 2020-04-25
|
||||
* @project: WarpConverter
|
||||
*/
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class YmlConfiguration extends YamlConfiguration {
|
||||
|
||||
private final DumperOptions yamlOptions = new DumperOptions();
|
||||
private final Representer yamlRepresenter = new YamlRepresenter();
|
||||
private final Yaml yaml = new Yaml(new YamlConstructor(), yamlRepresenter, yamlOptions);
|
||||
private Map<Integer, String> commentContainer = new HashMap<>();
|
||||
|
||||
public void save(File file) throws IOException {
|
||||
Validate.notNull(file);
|
||||
|
||||
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8)) {
|
||||
writer.write(saveToString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void saveConfig(File file, YmlConfiguration config) {
|
||||
try {
|
||||
config.save(file);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String saveToString(){
|
||||
yamlOptions.setIndent(options().indent());
|
||||
yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
|
||||
String header = "";//buildHeader();
|
||||
String dump = yaml.dump(getValues(false));
|
||||
|
||||
if (dump.equals(BLANK_CONFIG)) {
|
||||
dump = Strings.EMPTY;
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int line = 0;
|
||||
for(String s : dump.split("\n")) {
|
||||
line++;
|
||||
while (commentContainer.containsKey(line)) {
|
||||
sb.append(commentContainer.get(line)).append("\n");
|
||||
line++;
|
||||
}
|
||||
sb.append(s).append("\n");
|
||||
}
|
||||
|
||||
dump = sb.toString();
|
||||
}
|
||||
|
||||
return header.length() > 0 ? header + dump : dump;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Reader reader) throws IOException, InvalidConfigurationException {
|
||||
BufferedReader input = reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
try {
|
||||
String line;
|
||||
int count = 0;
|
||||
while ((line = input.readLine()) != null) {
|
||||
count++;
|
||||
if (line.contains(COMMENT_PREFIX)|| line.isEmpty())
|
||||
commentContainer.put(count, line);
|
||||
builder.append(line).append('\n');
|
||||
}
|
||||
} finally {
|
||||
input.close();
|
||||
}
|
||||
|
||||
loadFromString(builder.toString());
|
||||
}
|
||||
|
||||
public static YamlConfiguration loadConfiguration(File file, YmlConfiguration config) {
|
||||
Validate.notNull(file, "File cannot be null");
|
||||
|
||||
try {
|
||||
config.load(file);
|
||||
} catch (FileNotFoundException ex) {
|
||||
} catch (IOException | InvalidConfigurationException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Cannot load " + file, ex);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
private final DumperOptions yamlOptions = new DumperOptions();
|
||||
private final Representer yamlRepresenter = new YamlRepresenter();
|
||||
private final Yaml yaml = new Yaml(new YamlConstructor(), yamlRepresenter, yamlOptions);
|
||||
private Map<Integer, String> commentContainer = new HashMap<>();
|
||||
|
||||
@Override public void save(File file) throws IOException {
|
||||
Validate.notNull(file);
|
||||
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8)) {
|
||||
writer.write(saveToString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveConfig(File file, YmlConfiguration config) {
|
||||
try {
|
||||
config.save(file);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String saveToString(){
|
||||
yamlOptions.setIndent(options().indent());
|
||||
yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
String header = "";//buildHeader();
|
||||
String dump = yaml.dump(getValues(false));
|
||||
|
||||
if (dump.equals(BLANK_CONFIG)) {
|
||||
dump = Strings.EMPTY;
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int line = 0;
|
||||
for(String s : dump.split("\n")) {
|
||||
line++;
|
||||
while (commentContainer.containsKey(line)) {
|
||||
sb.append(commentContainer.get(line)).append("\n");
|
||||
line++;
|
||||
}
|
||||
sb.append(s).append("\n");
|
||||
}
|
||||
|
||||
dump = sb.toString();
|
||||
}
|
||||
return header.length() > 0 ? header + dump : dump;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Reader reader) throws IOException, InvalidConfigurationException {
|
||||
BufferedReader input = reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try {
|
||||
String line;
|
||||
int count = 0;
|
||||
while ((line = input.readLine()) != null) {
|
||||
count++;
|
||||
if (line.contains(COMMENT_PREFIX)|| line.isEmpty()) {
|
||||
commentContainer.put(count, line);
|
||||
}
|
||||
builder.append(line).append('\n');
|
||||
}
|
||||
} finally {
|
||||
input.close();
|
||||
}
|
||||
loadFromString(builder.toString());
|
||||
}
|
||||
|
||||
public static YamlConfiguration loadConfiguration(File file, YmlConfiguration config) {
|
||||
Validate.notNull(file, "File cannot be null");
|
||||
try {
|
||||
config.load(file);
|
||||
} catch (FileNotFoundException ex) {
|
||||
} catch (IOException | InvalidConfigurationException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Cannot load " + file, ex);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
}
|
||||
@@ -22,10 +22,10 @@ import com.github.joelgodofwar.mmh.MoreMobHeads;
|
||||
public class NameTag {
|
||||
|
||||
public static boolean canWearHead(LivingEntity mob) {
|
||||
if(mob instanceof Skeleton||mob instanceof Zombie||mob instanceof PigZombie||mob instanceof Villager||
|
||||
mob instanceof Drowned||mob instanceof Stray||mob instanceof Husk||mob instanceof WitherSkeleton||
|
||||
mob instanceof ZombieVillager||mob instanceof Evoker||mob instanceof WanderingTrader||mob instanceof Vex||
|
||||
mob instanceof Illusioner||mob instanceof Pillager||mob instanceof Vindicator){
|
||||
if((mob instanceof Skeleton)||(mob instanceof Zombie)||(mob instanceof PigZombie)||(mob instanceof Villager)||
|
||||
(mob instanceof Drowned)||(mob instanceof Stray)||(mob instanceof Husk)||(mob instanceof WitherSkeleton)||
|
||||
(mob instanceof ZombieVillager)||(mob instanceof Evoker)||(mob instanceof WanderingTrader)||(mob instanceof Vex)||
|
||||
(mob instanceof Illusioner)||(mob instanceof Pillager)||(mob instanceof Vindicator)){
|
||||
return true;
|
||||
}
|
||||
double vers = Double.parseDouble( MoreMobHeads.getMCVersion().substring(2, 4) ); // 1.16.2
|
||||
|
||||
Reference in new issue
Block a user