diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index 212ac4d6ed..80381e9ae7 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -92,6 +92,12 @@ 4.12 test + + org.mockito + mockito-all + 1.10.19 + test + diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java index 058c3605f6..9ce6c50be1 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java @@ -42,6 +42,7 @@ import javax.imageio.ImageIO; import joptsimple.OptionParser; import joptsimple.OptionSet; import net.runelite.api.Client; +import net.runelite.client.config.ConfigManager; import net.runelite.client.account.AccountSession; import net.runelite.client.events.SessionClose; import net.runelite.client.events.SessionOpen; @@ -57,6 +58,7 @@ public class RuneLite private static final Logger logger = LoggerFactory.getLogger(RuneLite.class); public static final File RUNELITE_DIR = new File(System.getProperty("user.home"), ".runelite"); + public static final File PROFILES_DIR = new File(RUNELITE_DIR, "profiles"); public static final File SESSION_FILE = new File(RUNELITE_DIR, "session"); public static Image ICON; @@ -75,6 +77,7 @@ public class RuneLite private WSClient wsclient; private AccountSession accountSession; + private ConfigManager configManager = new ConfigManager(eventBus); static { @@ -99,6 +102,8 @@ public class RuneLite parser.accepts("no-rs"); options = parser.parse(args); + PROFILES_DIR.mkdirs(); + runelite = new RuneLite(); runelite.start(); } @@ -109,6 +114,8 @@ public class RuneLite setupTrayIcon(); + configManager.load(); + eventBus.register(menuManager); pluginManager = new PluginManager(this); @@ -210,6 +217,14 @@ public class RuneLite accountSession = session; + if (session.getUsername() != null) + { + // Initialize config for new session + // If the session isn't logged in yet, don't switch to the new config + configManager = new ConfigManager(eventBus, session); + configManager.load(); + } + eventBus.post(new SessionOpen()); } @@ -230,6 +245,10 @@ public class RuneLite accountSession = null; // No more account + // Restore config + configManager = new ConfigManager(eventBus); + configManager.load(); + eventBus.post(new SessionClose()); } @@ -293,6 +312,11 @@ public class RuneLite return trayIcon; } + public ConfigManager getConfigManager() + { + return configManager; + } + public AccountSession getAccountSession() { return accountSession; diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigDescriptor.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigDescriptor.java new file mode 100644 index 0000000000..34db13d2e9 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigDescriptor.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.config; + +import java.util.Collection; + +public class ConfigDescriptor +{ + private final ConfigGroup group; + private final Collection items; + + public ConfigDescriptor(ConfigGroup group, Collection items) + { + this.group = group; + this.items = items; + } + + public ConfigGroup getGroup() + { + return group; + } + + public Collection getItems() + { + return items; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigGroup.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigGroup.java new file mode 100644 index 0000000000..434fd4ca9d --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigGroup.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ConfigGroup +{ + String keyName(); + + String name(); + + String description(); +} diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java new file mode 100644 index 0000000000..9cea084db8 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.config; + +import com.google.common.base.Objects; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class ConfigInvocationHandler implements InvocationHandler +{ + private static final Logger logger = LoggerFactory.getLogger(ConfigInvocationHandler.class); + + private final ConfigManager manager; + + public ConfigInvocationHandler(ConfigManager manager) + { + this.manager = manager; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + Class iface = proxy.getClass().getInterfaces()[0]; + + ConfigGroup group = iface.getAnnotation(ConfigGroup.class); + ConfigItem item = method.getAnnotation(ConfigItem.class); + + if (group == null) + { + logger.warn("Configuration proxy class {} has no @ConfigGroup!", proxy.getClass()); + return null; + } + + if (item == null) + { + logger.warn("Configuration method {} has no @ConfigItem!", method); + return null; + } + + if (args == null) + { + // Getting configuration item + String value = manager.getConfiguration(group.keyName(), item.keyName()); + + if (value == null) + { + if (method.isDefault()) + { + return callDefaultMethod(proxy, method, args); + } + + return null; + } + + // Convert value to return type + Class returnType = method.getReturnType(); + if (returnType == value.getClass()) + { + return value; + } + + if (returnType == Boolean.class) + { + return Boolean.valueOf(value); + } + + logger.warn("Unknown return type for configuration item {}.{}: {}", group.keyName(), item.keyName(), returnType); + return null; + } + else + { + // Setting a configuration value + + if (args.length != 1) + { + throw new RuntimeException("Invalid number of arguents to configuration method"); + } + + Object newValue = args[0]; + + if (method.isDefault()) + { + Object defaultValue = callDefaultMethod(proxy, method, args); + + if (Objects.equal(newValue, defaultValue)) + { + // Just unset if it goes back to the default + manager.unsetConfiguration(group.keyName(), item.keyName()); + return null; + } + } + + manager.setConfiguration(group.keyName(), item.keyName(), args[0].toString()); + return null; + } + } + + private Object callDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable + { + // Call the default method implementation - https://rmannibucau.wordpress.com/2014/03/27/java-8-default-interface-methods-and-jdk-dynamic-proxies/ + Constructor constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class); + constructor.setAccessible(true); + + Class declaringClass = method.getDeclaringClass(); + return constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE) + .unreflectSpecial(method, declaringClass) + .bindTo(proxy) + .invokeWithArguments(args); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigItem.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigItem.java new file mode 100644 index 0000000000..9897e91bbd --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigItem.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface ConfigItem +{ + String keyName(); + + String name(); + + String description(); +} diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigItemDescriptor.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigItemDescriptor.java new file mode 100644 index 0000000000..1607f66571 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigItemDescriptor.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.config; + +public class ConfigItemDescriptor +{ + private final ConfigItem item; + private final Class type; + + public ConfigItemDescriptor(ConfigItem item, Class type) + { + this.item = item; + this.type = type; + } + + public ConfigItem getItem() + { + return item; + } + + public Class getType() + { + return type; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java new file mode 100644 index 0000000000..24a5ff2810 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.config; + +import com.google.common.eventbus.EventBus; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.stream.Collectors; +import net.runelite.client.RuneLite; +import net.runelite.client.account.AccountSession; +import net.runelite.client.events.ConfigChanged; +import net.runelite.http.api.config.ConfigClient; +import net.runelite.http.api.config.ConfigEntry; +import net.runelite.http.api.config.Configuration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConfigManager +{ + private static final Logger logger = LoggerFactory.getLogger(ConfigManager.class); + + private static final String SETTINGS_FILE_NAME = "settings.properties"; + + private final EventBus eventBus; + private AccountSession session; + private ConfigClient client; + + private final File propertiesFile; + private final ConfigInvocationHandler handler = new ConfigInvocationHandler(this); + private final Properties properties = new Properties(); + + public ConfigManager(EventBus eventBus) + { + this.eventBus = eventBus; + this.propertiesFile = getPropertiesFile(); + } + + public ConfigManager(EventBus eventBus, AccountSession session) + { + this.eventBus = eventBus; + this.session = session; + // if session username is null then dont.. + this.client = new ConfigClient(session.getUuid()); + this.propertiesFile = getPropertiesFile(); + } + + private File getPropertiesFile() + { + // Sessions that aren't logged in have no username + if (session == null || session.getUsername() == null) + { + return new File(RuneLite.RUNELITE_DIR, SETTINGS_FILE_NAME); + } + else + { + File profileDir = new File(RuneLite.PROFILES_DIR, session.getUsername().toLowerCase()); + return new File(profileDir, SETTINGS_FILE_NAME); + } + } + + public void load() + { + if (client == null) + { + loadFromFile(); + return; + } + + Configuration configuration; + + try + { + configuration = client.get(); + } + catch (IOException ex) + { + logger.debug("Unable to load configuration from client, using saved configuration from disk", ex); + loadFromFile(); + return; + } + + if (configuration.getConfig().isEmpty()) + { + logger.debug("No configuration from client, using saved configuration on disk"); + loadFromFile(); + return; + } + + properties.clear(); + + for (ConfigEntry entry : configuration.getConfig()) + { + properties.setProperty(entry.getKey(), entry.getValue()); + } + + try + { + saveToFile(); + + logger.debug("Updated configuration on disk with the latest version"); + } + catch (IOException ex) + { + logger.warn("Unable to update configuration on disk", ex); + } + } + + private void loadFromFile() + { + try (FileInputStream in = new FileInputStream(propertiesFile)) + { + properties.load(in); + } + catch (FileNotFoundException ex) + { + logger.debug("Unable to load settings - no such file"); + } + catch (IOException ex) + { + logger.warn("Unable to load settings", ex); + } + } + + private void saveToFile() throws IOException + { + propertiesFile.getParentFile().mkdirs(); + + try (FileOutputStream out = new FileOutputStream(propertiesFile)) + { + properties.store(out, "Runelite configuration"); + } + } + + public T getConfig(Class clazz) + { + if (!Modifier.isPublic(clazz.getModifiers())) + { + throw new RuntimeException("Non-public configuration classes can't have default methods invoked"); + } + + return (T) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] + { + clazz + }, handler); + } + + public String getConfiguration(String groupName, String key) + { + return properties.getProperty(groupName + "." + key); + } + + public void setConfiguration(String groupName, String key, String value) + { + logger.debug("Setting configuration value for {}.{} to {}", groupName, key, value); + + String oldValue = (String) properties.setProperty(groupName + "." + key, value); + + if (client != null) + { + try + { + client.set(groupName + "." + key, value); + } + catch (IOException ex) + { + logger.warn("unable to set configuration item", ex); + } + } + + try + { + saveToFile(); + } + catch (IOException ex) + { + logger.warn("unable to save configuration file", ex); + } + + ConfigChanged configChanged = new ConfigChanged(); + configChanged.setGroup(groupName); + configChanged.setKey(key); + configChanged.setOldValue(oldValue); + configChanged.setNewValue(value); + + eventBus.post(configChanged); + } + + public void unsetConfiguration(String groupName, String key) + { + logger.debug("Unsetting configuration value for {}.{}", groupName, key); + + String oldValue = (String) properties.remove(groupName + "." + key); + + if (client != null) + { + try + { + client.unset(groupName + "." + key); + } + catch (IOException ex) + { + logger.warn("unable to set configuration item", ex); + } + } + + try + { + saveToFile(); + } + catch (IOException ex) + { + logger.warn("unable to save configuration file", ex); + } + + ConfigChanged configChanged = new ConfigChanged(); + configChanged.setGroup(groupName); + configChanged.setKey(key); + configChanged.setOldValue(oldValue); + + eventBus.post(configChanged); + } + + public ConfigDescriptor getConfigDescriptor(Object configurationProxy) + { + Class inter = configurationProxy.getClass().getInterfaces()[0]; + ConfigGroup group = inter.getAnnotation(ConfigGroup.class); + + if (group == null) + { + throw new IllegalArgumentException("Not a config group"); + } + + List items = Arrays.stream(inter.getMethods()) + .filter(m -> m.getParameterCount() == 0) + .map(m -> new ConfigItemDescriptor( + m.getDeclaredAnnotation(ConfigItem.class), + m.getReturnType() + )) + .collect(Collectors.toList()); + return new ConfigDescriptor(group, items); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/events/ConfigChanged.java b/runelite-client/src/main/java/net/runelite/client/events/ConfigChanged.java new file mode 100644 index 0000000000..ba30737994 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/events/ConfigChanged.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.events; + +public class ConfigChanged +{ + private String group; + private String key; + private String oldValue; + private String newValue; + + public String getGroup() + { + return group; + } + + public void setGroup(String group) + { + this.group = group; + } + + public String getKey() + { + return key; + } + + public void setKey(String key) + { + this.key = key; + } + + public String getOldValue() + { + return oldValue; + } + + public void setOldValue(String oldValue) + { + this.oldValue = oldValue; + } + + public String getNewValue() + { + return newValue; + } + + public void setNewValue(String newValue) + { + this.newValue = newValue; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/Plugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/Plugin.java index d2e4967592..6b4ae68652 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/Plugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/Plugin.java @@ -44,11 +44,17 @@ public abstract class Plugin extends AbstractIdleService return overlay != null ? Arrays.asList(overlay) : Collections.EMPTY_LIST; } + public Object getConfig() + { + return null; + } + /** * Override AbstractIdleService's default executor to instead execute in * the main thread. Prevents plugins from all being initialized from * different threads, which causes the plugin order on the navbar to be * undefined + * * @return */ @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java index 9b76189696..b898cae92f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java @@ -36,6 +36,7 @@ import net.runelite.client.plugins.account.AccountPlugin; import net.runelite.client.plugins.boosts.Boosts; import net.runelite.client.plugins.bosstimer.BossTimers; import net.runelite.client.plugins.clanchat.ClanChat; +import net.runelite.client.plugins.config.ConfigPlugin; import net.runelite.client.plugins.devtools.DevTools; import net.runelite.client.plugins.fpsinfo.FPS; import net.runelite.client.plugins.hiscore.Hiscore; @@ -77,6 +78,7 @@ public class PluginManager plugins.add(new ClanChat()); plugins.add(new Zulrah()); plugins.add(new AccountPlugin()); + plugins.add(new ConfigPlugin()); if (RuneLite.getOptions().has("developer-mode")) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java new file mode 100644 index 0000000000..f9fbac101c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.config; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.swing.BoxLayout; +import static javax.swing.BoxLayout.Y_AXIS; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import net.runelite.client.RuneLite; +import net.runelite.client.config.ConfigDescriptor; +import net.runelite.client.config.ConfigItemDescriptor; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginManager; +import net.runelite.client.ui.PluginPanel; +import static net.runelite.client.ui.PluginPanel.PANEL_HEIGHT; +import static net.runelite.client.ui.PluginPanel.PANEL_WIDTH; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConfigPanel extends PluginPanel +{ + private static final Logger logger = LoggerFactory.getLogger(ConfigPanel.class); + + private final RuneLite runelite = RuneLite.getRunelite(); + + public ConfigPanel() + { + setMinimumSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT)); + setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT)); + setSize(PANEL_WIDTH, PANEL_HEIGHT); + setLayout(new BorderLayout()); + setVisible(true); + } + + @Override + public boolean equals(Object other) + { + return other.getClass() == this.getClass(); + } + + public void init() + { + add(createConfigPanel()); + } + + private Collection getConfig() + { + List list = new ArrayList<>(); + PluginManager pm = runelite.getPluginManager(); + for (Plugin plugin : pm.getPlugins()) + { + Object config = plugin.getConfig(); + if (config != null) + { + ConfigManager configManager = runelite.getConfigManager(); + ConfigDescriptor configDescriptor = configManager.getConfigDescriptor(config); + list.add(configDescriptor); + } + } + return list; + } + + private JPanel createConfigPanel() + { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, Y_AXIS)); + + ConfigManager configManager = runelite.getConfigManager(); + Collection config = getConfig(); + for (ConfigDescriptor cd : config) + { + JPanel groupPanel = new JPanel(); + groupPanel.setLayout(new BorderLayout()); + + groupPanel.add(new JLabel(cd.getGroup().name()), BorderLayout.NORTH); + + JPanel itemPanel = new JPanel(); + + for (ConfigItemDescriptor cid : cd.getItems()) + { + itemPanel.add(new JLabel(cid.getItem().name())); + + if (cid.getType() == boolean.class) + { + JCheckBox checkbox = new JCheckBox(); + checkbox.setSelected(Boolean.parseBoolean(configManager.getConfiguration(cd.getGroup().keyName(), cid.getItem().keyName()))); + checkbox.addActionListener(ae -> changeConfiguration(ae, checkbox, cd, cid)); + + itemPanel.add(checkbox); + } + } + + groupPanel.add(itemPanel, BorderLayout.CENTER); + panel.add(groupPanel); + } + return panel; + } + + private void changeConfiguration(ActionEvent ae, JCheckBox checkbox, ConfigDescriptor cd, ConfigItemDescriptor cid) + { + ConfigManager configManager = runelite.getConfigManager(); + configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), "" + checkbox.isSelected()); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPlugin.java new file mode 100644 index 0000000000..193724eaa1 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPlugin.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.config; + +import java.awt.event.ActionEvent; +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; +import net.runelite.client.RuneLite; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.ui.ClientUI; +import net.runelite.client.ui.NavigationButton; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ConfigPlugin extends Plugin +{ + private static final Logger logger = LoggerFactory.getLogger(ConfigPlugin.class); + + private final NavigationButton navButton = new NavigationButton("Configuration"); + private final RuneLite runelite = RuneLite.getRunelite(); + private final ClientUI ui = runelite.getGui(); + + @Override + protected void startUp() throws Exception + { + navButton.getButton().addActionListener(this::setPluginPanel); + + ImageIcon icon = new ImageIcon(ImageIO.read(getClass().getResourceAsStream("config_icon.png"))); + navButton.getButton().setIcon(icon); + + ui.getNavigationPanel().addNavigation(navButton); + } + + @Override + protected void shutDown() throws Exception + { + } + + private void setPluginPanel(ActionEvent ae) + { + ConfigPanel panel = new ConfigPanel(); + panel.init(); + + ui.expand(panel); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentConfig.java new file mode 100644 index 0000000000..1d091cea85 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentConfig.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.opponentinfo; + +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup( + keyName = "oppinfo", + name = "Opponent Info", + description = "Configuration for the opponent info plugin" +) +public interface OpponentConfig +{ + @ConfigItem( + keyName = "enabled", + name = "Enabled", + description = "Configures whether or not opponent info is displayed" + ) + default boolean enabled() + { + return true; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfo.java b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfo.java index 8a25fcb71b..1d072d5660 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfo.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfo.java @@ -30,12 +30,14 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Type; import java.util.Map; +import net.runelite.client.RuneLite; import net.runelite.client.plugins.Plugin; import net.runelite.client.ui.overlay.Overlay; public class OpponentInfo extends Plugin { - private final Overlay overlay = new OpponentInfoOverlay(); + private final OpponentConfig config = RuneLite.getRunelite().getConfigManager().getConfig(OpponentConfig.class); + private final Overlay overlay = new OpponentInfoOverlay(this); @Override public Overlay getOverlay() @@ -53,10 +55,18 @@ public class OpponentInfo extends Plugin { } + @Override + public OpponentConfig getConfig() + { + return config; + } + public static Map loadNpcHealth() { Gson gson = new Gson(); - Type type = new TypeToken>(){}.getType(); + Type type = new TypeToken>() + { + }.getType(); InputStream healthFile = OpponentInfo.class.getResourceAsStream("/npc_health.json"); return gson.fromJson(new InputStreamReader(healthFile), type); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoOverlay.java index 25556064f5..8554bb0a63 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoOverlay.java @@ -22,7 +22,6 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package net.runelite.client.plugins.opponentinfo; import java.awt.Color; @@ -58,6 +57,7 @@ class OpponentInfoOverlay extends Overlay private static final Duration WAIT = Duration.ofSeconds(3); + private final OpponentConfig config; private Integer lastMaxHealth; private DecimalFormat df = new DecimalFormat("0.0"); private float lastRatio = 0; @@ -65,9 +65,10 @@ class OpponentInfoOverlay extends Overlay private String opponentName; private Map oppInfoHealth = OpponentInfo.loadNpcHealth(); - OpponentInfoOverlay() + OpponentInfoOverlay(OpponentInfo plugin) { super(OverlayPosition.TOP_LEFT, OverlayPriority.HIGH); + this.config = plugin.getConfig(); } private Actor getOpponent() @@ -76,7 +77,9 @@ class OpponentInfoOverlay extends Overlay Player player = client.getLocalPlayer(); if (player == null) + { return null; + } return player.getInteracting(); } @@ -84,8 +87,10 @@ class OpponentInfoOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { - if (RuneLite.getClient().getGameState() != GameState.LOGGED_IN) + if (RuneLite.getClient().getGameState() != GameState.LOGGED_IN || config.enabled() == false) + { return null; + } Actor opponent = getOpponent(); @@ -98,8 +103,9 @@ class OpponentInfoOverlay extends Overlay } if (Duration.between(Instant.now(), lastTime).abs().compareTo(WAIT) > 0) + { return null; //don't draw anything. - + } FontMetrics fm = graphics.getFontMetrics(); int height = TOP_BORDER + fm.getHeight(); // opponent name diff --git a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java index 7a9374e414..28aee0fc27 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java @@ -28,6 +28,7 @@ import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.util.Objects; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -99,7 +100,7 @@ public final class ClientUI extends JFrame public void expand(PluginPanel panel) { - if (pluginPanel == panel) + if (Objects.equals(pluginPanel, panel)) { navContainer.remove(1); container.validate(); diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/config_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/config_icon.png new file mode 100644 index 0000000000..09626e93cf Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/config/config_icon.png differ diff --git a/runelite-client/src/test/java/net/runelite/client/config/ConfigManagerTest.java b/runelite-client/src/test/java/net/runelite/client/config/ConfigManagerTest.java new file mode 100644 index 0000000000..75c80695c5 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/config/ConfigManagerTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.config; + +import com.google.common.eventbus.EventBus; +import java.io.IOException; +import java.time.Instant; +import java.util.UUID; +import net.runelite.client.account.AccountSession; +import org.junit.Assert; +import org.junit.Test; +import static org.mockito.Mockito.mock; + +public class ConfigManagerTest +{ + @Test + public void testGetConfig() throws IOException + { + AccountSession accountSession = new AccountSession(); + accountSession.setUuid(UUID.randomUUID()); + accountSession.setUsername("test"); + accountSession.setCreated(Instant.now()); + + ConfigManager manager = new ConfigManager(mock(EventBus.class)); + manager.setConfiguration("test", "key", "moo"); + + TestConfig conf = manager.getConfig(TestConfig.class); + Assert.assertEquals("moo", conf.key()); + } + + @Test + public void testGetConfigDefault() throws IOException + { + AccountSession accountSession = new AccountSession(); + accountSession.setUuid(UUID.randomUUID()); + accountSession.setUsername("test"); + accountSession.setCreated(Instant.now()); + + ConfigManager manager = new ConfigManager(mock(EventBus.class)); + + TestConfig conf = manager.getConfig(TestConfig.class); + Assert.assertEquals("default", conf.key()); + } + + @Test + public void testSetConfig() throws IOException + { + AccountSession accountSession = new AccountSession(); + accountSession.setUuid(UUID.randomUUID()); + accountSession.setUsername("test"); + accountSession.setCreated(Instant.now()); + + ConfigManager manager = new ConfigManager(mock(EventBus.class)); + + TestConfig conf = manager.getConfig(TestConfig.class); + conf.key("new value"); + + Assert.assertEquals("new value", conf.key()); + } + + @Test + public void testGetConfigDescriptor() throws IOException + { + AccountSession accountSession = new AccountSession(); + accountSession.setUuid(UUID.randomUUID()); + accountSession.setUsername("test"); + accountSession.setCreated(Instant.now()); + + ConfigManager manager = new ConfigManager(mock(EventBus.class)); + + TestConfig conf = manager.getConfig(TestConfig.class); + ConfigDescriptor descriptor = manager.getConfigDescriptor(conf); + Assert.assertEquals(1, descriptor.getItems().size()); + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/config/TestConfig.java b/runelite-client/src/test/java/net/runelite/client/config/TestConfig.java new file mode 100644 index 0000000000..7b2bfe02da --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/config/TestConfig.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.config; + +@ConfigGroup( + keyName = "test", + name = "test", + description = "test" +) +public interface TestConfig +{ + @ConfigItem( + keyName = "key", + name = "Key Name", + description = "value" + ) + default String key() + { + return "default"; + } + + @ConfigItem( + keyName = "key", + name = "Key Name", + description = "value" + ) + void key(String key); +}