3
0
Mirror von https://github.com/ViaVersion/ViaVersion.git synchronisiert 2024-10-03 08:41:05 +02:00

Config for protocol versions

Also make config concurrent
Dieser Commit ist enthalten in:
Myles 2016-10-02 19:40:38 +01:00
Ursprung 3fe25f68b1
Commit 21c957b8d5
12 geänderte Dateien mit 209 neuen und 40 gelöschten Zeilen

Datei anzeigen

@ -8,9 +8,10 @@ import us.myles.ViaVersion.util.Config;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
public class BukkitConfigAPI extends Config implements ViaVersionConfig { public class BukkitConfigAPI extends Config implements ViaVersionConfig {
private static List<String> UNSUPPORTED = Arrays.asList(); private static List<String> UNSUPPORTED = Arrays.asList("bungee-ping-interval", "bungee-ping-save", "bungee-servers");
public BukkitConfigAPI() { public BukkitConfigAPI() {
super(new File(((ViaVersionPlugin) Via.getPlatform()).getDataFolder(), "config.yml")); super(new File(((ViaVersionPlugin) Via.getPlatform()).getDataFolder(), "config.yml"));
@ -166,6 +167,11 @@ public class BukkitConfigAPI extends Config implements ViaVersionConfig {
return getString("reload-disconnect-msg", "Server reload, please rejoin!"); return getString("reload-disconnect-msg", "Server reload, please rejoin!");
} }
@Override
protected void handleConfig(Map<String, Object> config) {
// Nothing currently
}
@Override @Override
public List<String> getUnsupportedOptions() { public List<String> getUnsupportedOptions() {
return UNSUPPORTED; return UNSUPPORTED;

Datei anzeigen

@ -58,8 +58,6 @@ public class BungeePlugin extends Plugin implements ViaPlatform, Listener {
.loader(new BungeeViaLoader(this)) .loader(new BungeeViaLoader(this))
.commandHandler(commandHandler) .commandHandler(commandHandler)
.build()); .build());
getProxy().getPluginManager().registerListener(this, this);
} }
@Override @Override
@ -137,7 +135,7 @@ public class BungeePlugin extends Plugin implements ViaPlatform, Listener {
} }
@Override @Override
public ViaVersionConfig getConf() { public BungeeConfigAPI getConf() {
return config; return config;
} }
@ -160,7 +158,7 @@ public class BungeePlugin extends Plugin implements ViaPlatform, Listener {
plugins.add(new PluginInfo(true, p.getDescription().getName(), p.getDescription().getVersion(), p.getDescription().getMain(), Arrays.asList(p.getDescription().getAuthor()))); plugins.add(new PluginInfo(true, p.getDescription().getName(), p.getDescription().getVersion(), p.getDescription().getMain(), Arrays.asList(p.getDescription().getAuthor())));
platformSpecific.add("plugins", GsonUtil.getGson().toJsonTree(plugins)); platformSpecific.add("plugins", GsonUtil.getGson().toJsonTree(plugins));
platformSpecific.add("servers", GsonUtil.getGson().toJsonTree(ProtocolDetectorService.getProtocolIds())); platformSpecific.add("servers", GsonUtil.getGson().toJsonTree(ProtocolDetectorService.getDetectedIds()));
return platformSpecific; return platformSpecific;
} }

Datei anzeigen

@ -102,12 +102,6 @@ public class BungeeEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
storage.setCurrentServer(serverName); storage.setCurrentServer(serverName);
// TODO HANDLE
if (!ProtocolDetectorService.hasProtocolId(serverName)) {
Via.getPlatform().getLogger().severe("Could not find the protocol id for server " + serverName);
return;
}
int protocolId = ProtocolDetectorService.getProtocolId(serverName); int protocolId = ProtocolDetectorService.getProtocolId(serverName);
UserConnection viaConnection = Via.getManager().getConnection(player.getUniqueId()); UserConnection viaConnection = Via.getManager().getConnection(player.getUniqueId());
@ -124,7 +118,6 @@ public class BungeeEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
pipeline.add(prot.getValue()); pipeline.add(prot.getValue());
} }
viaConnection.put(info); viaConnection.put(info);
viaConnection.put(storage); viaConnection.put(storage);
@ -137,7 +130,6 @@ public class BungeeEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
Object wrapper = ReflectionUtil.get(player, "ch", Object.class); Object wrapper = ReflectionUtil.get(player, "ch", Object.class);
wrapper.getClass().getDeclaredMethod("setVersion", int.class).invoke(wrapper, protocolId); wrapper.getClass().getDeclaredMethod("setVersion", int.class).invoke(wrapper, protocolId);
// ReflectionUtil.invoke(player, "init");
Object entityMap = Class.forName("net.md_5.bungee.entitymap.EntityMap").getDeclaredMethod("getEntityMap", int.class).invoke(null, protocolId); Object entityMap = Class.forName("net.md_5.bungee.entitymap.EntityMap").getDeclaredMethod("getEntityMap", int.class).invoke(null, protocolId);
ReflectionUtil.set(player, "entityRewrite", entityMap); ReflectionUtil.set(player, "entityRewrite", entityMap);

Datei anzeigen

@ -1,11 +1,12 @@
package us.myles.ViaVersion.bungee.platform; package us.myles.ViaVersion.bungee.platform;
import us.myles.ViaVersion.api.ViaVersionConfig; import us.myles.ViaVersion.api.ViaVersionConfig;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import us.myles.ViaVersion.bungee.providers.BungeeVersionProvider;
import us.myles.ViaVersion.util.Config; import us.myles.ViaVersion.util.Config;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.*;
import java.util.List;
public class BungeeConfigAPI extends Config implements ViaVersionConfig { public class BungeeConfigAPI extends Config implements ViaVersionConfig {
private static List<String> UNSUPPORTED = Arrays.asList("nms-player-ticking", "item-cache", "anti-xray-patch"); private static List<String> UNSUPPORTED = Arrays.asList("nms-player-ticking", "item-cache", "anti-xray-patch");
@ -14,6 +15,38 @@ public class BungeeConfigAPI extends Config implements ViaVersionConfig {
super(new File(configFile, "config.yml")); super(new File(configFile, "config.yml"));
} }
@Override
protected void handleConfig(Map<String, Object> config) {
// Parse servers
Map<String, Object> servers;
if (!(config.get("bungee-servers") instanceof Map)) {
servers = new HashMap<>();
} else {
servers = (Map) config.get("bungee-servers");
}
// Convert any bad Protocol Ids
for (Map.Entry<String, Object> entry : new HashSet<>(servers.entrySet())) {
if (!(entry.getValue() instanceof Integer)) {
if (entry.getValue() instanceof String) {
ProtocolVersion found = ProtocolVersion.getClosest((String) entry.getValue());
if (found != null) {
servers.put(entry.getKey(), found.getId());
} else {
servers.remove(entry.getKey()); // Remove!
}
} else {
servers.remove(entry.getKey()); // Remove!
}
}
}
// Ensure default exists
if (!servers.containsKey("default")) {
servers.put("default", BungeeVersionProvider.getLowestSupportedVersion());
}
// Put back
config.put("bungee-servers", servers);
}
@Override @Override
public List<String> getUnsupportedOptions() { public List<String> getUnsupportedOptions() {
return UNSUPPORTED; return UNSUPPORTED;
@ -167,4 +200,33 @@ public class BungeeConfigAPI extends Config implements ViaVersionConfig {
public String getReloadDisconnectMsg() { public String getReloadDisconnectMsg() {
return getString("reload-disconnect-msg", "Server reload, please rejoin!"); return getString("reload-disconnect-msg", "Server reload, please rejoin!");
} }
/**
* What is the interval for checking servers via ping
* -1 for disabled
*
* @return Ping interval in seconds
*/
public int getBungeePingInterval() {
return getInt("bungee-ping-interval", 60);
}
/**
* Should the bungee ping be saved to the config on change.
*
* @return True if it should save
*/
public boolean isBungeePingSave() {
return getBoolean("bungee-ping-save", true);
}
/**
* Get the listed server protocols in the config.
* default will be listed as default.
*
* @return Map of String, Integer
*/
public Map<String, Integer> getBungeeServerProtocols() {
return get("bungee-servers", Map.class, new HashMap<>());
}
} }

Datei anzeigen

@ -1,6 +1,7 @@
package us.myles.ViaVersion.bungee.platform; package us.myles.ViaVersion.bungee.platform;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import net.md_5.bungee.api.ProxyServer;
import us.myles.ViaVersion.BungeePlugin; import us.myles.ViaVersion.BungeePlugin;
import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.platform.ViaPlatformLoader; import us.myles.ViaVersion.api.platform.ViaPlatformLoader;
@ -18,9 +19,13 @@ public class BungeeViaLoader implements ViaPlatformLoader {
@Override @Override
public void load() { public void load() {
// Listeners
ProxyServer.getInstance().getPluginManager().registerListener(plugin, plugin);
// Providers
Via.getManager().getProviders().use(MovementTransmitterProvider.class, new BungeeMovementTransmitter()); Via.getManager().getProviders().use(MovementTransmitterProvider.class, new BungeeMovementTransmitter());
Via.getManager().getProviders().use(VersionProvider.class, new BungeeVersionProvider()); Via.getManager().getProviders().use(VersionProvider.class, new BungeeVersionProvider());
if (plugin.getConf().getBungeePingInterval() > 0) {
plugin.getProxy().getScheduler().schedule(plugin, new ProtocolDetectorService(plugin), 0, 1, TimeUnit.MINUTES); plugin.getProxy().getScheduler().schedule(plugin, new ProtocolDetectorService(plugin), 0, plugin.getConf().getBungeePingInterval(), TimeUnit.SECONDS);
}
} }
} }

Datei anzeigen

@ -1,6 +1,7 @@
package us.myles.ViaVersion.bungee.providers; package us.myles.ViaVersion.bungee.providers;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import net.md_5.bungee.api.ProxyServer;
import us.myles.ViaVersion.api.data.UserConnection; import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.base.ProtocolInfo; import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.protocols.base.VersionProvider; import us.myles.ViaVersion.protocols.base.VersionProvider;
@ -11,7 +12,7 @@ import java.util.List;
public class BungeeVersionProvider extends VersionProvider { public class BungeeVersionProvider extends VersionProvider {
private static Class<?> ref; private static Class<?> ref;
public BungeeVersionProvider() { static {
try { try {
ref = Class.forName("net.md_5.bungee.protocol.ProtocolConstants"); ref = Class.forName("net.md_5.bungee.protocol.ProtocolConstants");
} catch (Exception e) { } catch (Exception e) {
@ -35,7 +36,7 @@ public class BungeeVersionProvider extends VersionProvider {
// Older than bungee supports, get the lowest version // Older than bungee supports, get the lowest version
if (info.getProtocolVersion() < list.get(0)) { if (info.getProtocolVersion() < list.get(0)) {
return list.get(0); return getLowestSupportedVersion();
} }
// Loop through all protocols to get the closest protocol id that bungee supports // Loop through all protocols to get the closest protocol id that bungee supports
@ -47,4 +48,18 @@ public class BungeeVersionProvider extends VersionProvider {
System.out.println("Panic, no protocol id found for " + info.getProtocolVersion()); System.out.println("Panic, no protocol id found for " + info.getProtocolVersion());
return info.getProtocolVersion(); return info.getProtocolVersion();
} }
public static int getLowestSupportedVersion() {
List<Integer> list;
try {
list = ReflectionUtil.getStatic(ref, "SUPPORTED_VERSION_IDS", List.class);
return list.get(0);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
// Fallback
return ProxyServer.getInstance().getProtocolVersion();
}
} }

Datei anzeigen

@ -2,16 +2,22 @@ package us.myles.ViaVersion.bungee.service;
import lombok.Getter; import lombok.Getter;
import net.md_5.bungee.api.Callback; import net.md_5.bungee.api.Callback;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.ServerPing; import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.config.ServerInfo;
import us.myles.ViaVersion.BungeePlugin; import us.myles.ViaVersion.BungeePlugin;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.bungee.platform.BungeeConfigAPI;
import us.myles.ViaVersion.bungee.providers.BungeeVersionProvider;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public class ProtocolDetectorService implements Runnable { public class ProtocolDetectorService implements Runnable {
private static final Map<String, Integer> protocolIds = new ConcurrentHashMap<>(); private static final Map<String, Integer> detectedProtocolIds = new ConcurrentHashMap<>();
private BungeePlugin plugin; private BungeePlugin plugin;
@Getter @Getter
private static ProtocolDetectorService instance; private static ProtocolDetectorService instance;
@ -22,13 +28,21 @@ public class ProtocolDetectorService implements Runnable {
} }
public static Integer getProtocolId(String serverName) { public static Integer getProtocolId(String serverName) {
if (!hasProtocolId(serverName)) // Step 1. Check Config
return -1; Map<String, Integer> servers = ((BungeeConfigAPI) Via.getConfig()).getBungeeServerProtocols();
return protocolIds.get(serverName); if (servers.containsKey(serverName)) {
} return servers.get(serverName);
}
public static boolean hasProtocolId(String serverName) { // Step 2. Check Detected
return protocolIds.containsKey(serverName); if (detectedProtocolIds.containsKey(serverName)) {
return detectedProtocolIds.get(serverName);
}
// Step 3. Use Default
if (servers.containsKey("default")) {
return servers.get("default");
}
// Step 4: Use bungee lowest supported... *cries*
return BungeeVersionProvider.getLowestSupportedVersion();
} }
@Override @Override
@ -42,14 +56,27 @@ public class ProtocolDetectorService implements Runnable {
value.ping(new Callback<ServerPing>() { value.ping(new Callback<ServerPing>() {
@Override @Override
public void done(ServerPing serverPing, Throwable throwable) { public void done(ServerPing serverPing, Throwable throwable) {
if (throwable == null) if (throwable == null) {
protocolIds.put(key, serverPing.getVersion().getProtocol()); detectedProtocolIds.put(key, serverPing.getVersion().getProtocol());
if (((BungeeConfigAPI) Via.getConfig()).isBungeePingSave()) {
Map<String, Integer> servers = ((BungeeConfigAPI) Via.getConfig()).getBungeeServerProtocols();
if (servers.containsKey(key)) {
if (servers.get(key) == serverPing.getVersion().getProtocol()) {
return;
}
}
// Save Server
servers.put(key, serverPing.getVersion().getProtocol());
// Save
Via.getPlatform().getConfigurationProvider().saveConfig();
}
}
} }
}); });
} }
public static Map<String, Integer> getProtocolIds() { public static Map<String, Integer> getDetectedIds() {
return new HashMap<>(protocolIds); return new HashMap<>(detectedProtocolIds);
} }
} }

Datei anzeigen

@ -51,7 +51,8 @@ public class ProtocolVersion {
register(v1_9_2 = new ProtocolVersion(109, "1.9.2")); register(v1_9_2 = new ProtocolVersion(109, "1.9.2"));
register(v1_9_3 = new ProtocolVersion(110, "1.9.3/4")); register(v1_9_3 = new ProtocolVersion(110, "1.9.3/4"));
register(v1_10 = new ProtocolVersion(210, "1.10")); register(v1_10 = new ProtocolVersion(210, "1.10"));
register(vSNAPSHOT = new ProtocolVersion(309, "1.11-SNAPSHOT")); // Snapshot uses colon as dashes are used other places...
register(vSNAPSHOT = new ProtocolVersion(309, "1.11:SNAPSHOT"));
register(unknown = new ProtocolVersion(-1, "UNKNOWN")); register(unknown = new ProtocolVersion(-1, "UNKNOWN"));
} }
@ -80,6 +81,24 @@ public class ProtocolVersion {
return Collections.unmodifiableList(new ArrayList<>(versions.values())); return Collections.unmodifiableList(new ArrayList<>(versions.values()));
} }
public static ProtocolVersion getClosest(String protocol) {
for (ProtocolVersion version : versions.values()) {
if (version.getName().equals(protocol))
return version;
if (version.getName().equals(protocol + ".x"))
return version;
String[] parts = version.getName().split("-");
for (String part : parts) {
if (part.equalsIgnoreCase(protocol)) {
return version;
}
if (part.equals(protocol + ".x"))
return version;
}
}
return null;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;

Datei anzeigen

@ -1,5 +1,6 @@
package us.myles.ViaVersion.util; package us.myles.ViaVersion.util;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
import us.myles.ViaVersion.api.configuration.ConfigurationProvider; import us.myles.ViaVersion.api.configuration.ConfigurationProvider;
@ -9,17 +10,21 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public abstract class Config implements ConfigurationProvider { public abstract class Config implements ConfigurationProvider {
private static ThreadLocal<Yaml> yaml = new ThreadLocal<Yaml>() { private static ThreadLocal<Yaml> yaml = new ThreadLocal<Yaml>() {
@Override @Override
protected Yaml initialValue() { protected Yaml initialValue() {
return new Yaml(); DumperOptions options = new DumperOptions();
// options.setPrettyFlow(true);
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
return new Yaml(options);
} }
}; };
private CommentStore commentStore = new CommentStore('.', 2); private CommentStore commentStore = new CommentStore('.', 2);
private final File configFile; private final File configFile;
private Map<String, Object> config; private ConcurrentHashMap<String, Object> config;
public Config(File configFile) { public Config(File configFile) {
this.configFile = configFile; this.configFile = configFile;
@ -70,12 +75,16 @@ public abstract class Config implements ConfigurationProvider {
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
// Call Handler
handleConfig(defaults);
// Save // Save
saveConfig(location, defaults); saveConfig(location, defaults);
return defaults; return defaults;
} }
protected abstract void handleConfig(Map<String, Object> config);
public void saveConfig(File location, Map<String, Object> config) { public void saveConfig(File location, Map<String, Object> config) {
try { try {
commentStore.writeComments(yaml.get().dump(config), location); commentStore.writeComments(yaml.get().dump(config), location);
@ -100,7 +109,7 @@ public abstract class Config implements ConfigurationProvider {
@Override @Override
public void reloadConfig() { public void reloadConfig() {
this.configFile.getParentFile().mkdirs(); this.configFile.getParentFile().mkdirs();
this.config = loadConfig(this.configFile); this.config = new ConcurrentHashMap<>(loadConfig(this.configFile));
} }
@Override @Override
@ -108,6 +117,14 @@ public abstract class Config implements ConfigurationProvider {
return this.config; return this.config;
} }
public <T> T get(String key, Class<T> clazz, T def) {
if (this.config.containsKey(key)) {
return (T) this.config.get(key);
} else {
return def;
}
}
public boolean getBoolean(String key, boolean def) { public boolean getBoolean(String key, boolean def) {
if (this.config.containsKey(key)) { if (this.config.containsKey(key)) {
return (boolean) this.config.get(key); return (boolean) this.config.get(key);

Datei anzeigen

@ -3,9 +3,10 @@
# If you need help: # If you need help:
# viaversion.com - Discussion tab # viaversion.com - Discussion tab
# IRC - https://elmer.spi.gt/iris/?nick=&channels=viaversion #viaversion on irc.spi.gt # IRC - https://elmer.spi.gt/iris/?nick=&channels=viaversion #viaversion on irc.spi.gt
# Docs - https://docs.viaversion.com/display/VIAVERSION/Configuration
# #
#----------------------------------------------------------# #----------------------------------------------------------#
# GLOBAL OPTIONS # # GLOBAL OPTIONS #
#----------------------------------------------------------# #----------------------------------------------------------#
# #
# Should ViaVersion check for updates? # Should ViaVersion check for updates?
@ -23,7 +24,29 @@ block-disconnect-msg: "You are using an unsupported Minecraft version!"
reload-disconnect-msg: "Server reload, please rejoin!" reload-disconnect-msg: "Server reload, please rejoin!"
# #
#----------------------------------------------------------# #----------------------------------------------------------#
# GLOBAL PACKET LIMITER # # BUNGEE OPTIONS #
#----------------------------------------------------------#
#
# BungeeCord allows you to have different server versions inside.
# Instead of you entering all the versions of these servers, we can ping them.
#
# What interval would you like us to ping at? (in seconds)
# Use -1 to disable.
bungee-ping-interval: 60
# If the above is enabled, should we save the info to the config (in the section below)
bungee-ping-save: true
# To get a servers protocol, ViaVersion will do the following:
# Look for the server in the following section, then look for the last ping if bungee-ping is enabled
# otherwise use default.
#
# The format for the following is:
# servername: protocolversion
# You can find protocol ids on http://wiki.vg/Protocol_version_numbers
# It will fallback to the default option if none found.
bungee-servers: {}
#
#----------------------------------------------------------#
# GLOBAL PACKET LIMITER #
#----------------------------------------------------------# #----------------------------------------------------------#
# #
# #

Datei anzeigen

@ -13,7 +13,6 @@ import org.spongepowered.api.scheduler.SpongeExecutorService;
import org.spongepowered.api.text.serializer.TextSerializers; import org.spongepowered.api.text.serializer.TextSerializers;
import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.ViaAPI; import us.myles.ViaVersion.api.ViaAPI;
import us.myles.ViaVersion.api.ViaVersionConfig;
import us.myles.ViaVersion.api.command.ViaCommandSender; import us.myles.ViaVersion.api.command.ViaCommandSender;
import us.myles.ViaVersion.api.configuration.ConfigurationProvider; import us.myles.ViaVersion.api.configuration.ConfigurationProvider;
import us.myles.ViaVersion.api.platform.TaskId; import us.myles.ViaVersion.api.platform.TaskId;
@ -162,7 +161,7 @@ public class SpongePlugin implements ViaPlatform {
} }
@Override @Override
public ViaVersionConfig getConf() { public SpongeConfigAPI getConf() {
return conf; return conf;
} }

Datei anzeigen

@ -6,14 +6,20 @@ import us.myles.ViaVersion.util.Config;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
public class SpongeConfigAPI extends Config implements ViaVersionConfig { public class SpongeConfigAPI extends Config implements ViaVersionConfig {
private static List<String> UNSUPPORTED = Arrays.asList("anti-xray-patch"); private static List<String> UNSUPPORTED = Arrays.asList("anti-xray-patch", "bungee-ping-interval", "bungee-ping-save", "bungee-servers");
public SpongeConfigAPI(File configFile) { public SpongeConfigAPI(File configFile) {
super(new File(configFile, "config.yml")); super(new File(configFile, "config.yml"));
} }
@Override
protected void handleConfig(Map<String, Object> config) {
// Nothing Currently
}
@Override @Override
public List<String> getUnsupportedOptions() { public List<String> getUnsupportedOptions() {
return UNSUPPORTED; return UNSUPPORTED;