Merge pull request #61 from TBMCPlugins/dev

New command system, fixes, improvements
This commit is contained in:
Norbi Peti 2019-02-01 17:07:49 +01:00 committed by GitHub
commit 98b73aaac3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 1092 additions and 590 deletions

View file

@ -1,13 +0,0 @@
<component name="libraryTable">
<library name="Maven: com.github.TBMCPlugins.ButtonCore:Towny:master-248b0d8d0a-1">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/github/TBMCPlugins/ButtonCore/Towny/master-248b0d8d0a-1/Towny-master-248b0d8d0a-1.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/github/TBMCPlugins/ButtonCore/Towny/master-248b0d8d0a-1/Towny-master-248b0d8d0a-1-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/github/TBMCPlugins/ButtonCore/Towny/master-248b0d8d0a-1/Towny-master-248b0d8d0a-1-sources.jar!/" />
</SOURCES>
</library>
</component>

View file

@ -1,13 +0,0 @@
<component name="libraryTable">
<library name="Maven: com.github.milkbowl:VaultAPI:master-431c5273c2-1">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/github/milkbowl/VaultAPI/master-431c5273c2-1/VaultAPI-master-431c5273c2-1.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/github/milkbowl/VaultAPI/master-431c5273c2-1/VaultAPI-master-431c5273c2-1-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/github/milkbowl/VaultAPI/master-431c5273c2-1/VaultAPI-master-431c5273c2-1-sources.jar!/" />
</SOURCES>
</library>
</component>

View file

@ -12,6 +12,7 @@
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" /> <orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
<orderEntry type="library" name="Maven: org.reflections:reflections:0.9.10" level="project" /> <orderEntry type="library" name="Maven: org.reflections:reflections:0.9.10" level="project" />
<orderEntry type="library" name="Maven: com.google.code.findbugs:annotations:2.0.1" level="project" /> <orderEntry type="library" name="Maven: com.google.code.findbugs:annotations:2.0.1" level="project" />
<orderEntry type="library" name="Maven: org.javassist:javassist:3.20.0-GA" level="project" /> <orderEntry type="library" name="Maven: org.javassist:javassist:3.20.0-GA" level="project" />
@ -19,6 +20,7 @@
<orderEntry type="library" scope="RUNTIME" name="Maven: net.bytebuddy:byte-buddy:1.6.11" level="project" /> <orderEntry type="library" scope="RUNTIME" name="Maven: net.bytebuddy:byte-buddy:1.6.11" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: net.bytebuddy:byte-buddy-agent:1.6.11" level="project" /> <orderEntry type="library" scope="RUNTIME" name="Maven: net.bytebuddy:byte-buddy-agent:1.6.11" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.objenesis:objenesis:2.5" level="project" /> <orderEntry type="library" scope="RUNTIME" name="Maven: org.objenesis:objenesis:2.5" level="project" />
<orderEntry type="module" module-name="ButtonProcessor" />
<orderEntry type="library" name="Maven: org.spigotmc:spigot-api:1.12.2-R0.1-SNAPSHOT" level="project" /> <orderEntry type="library" name="Maven: org.spigotmc:spigot-api:1.12.2-R0.1-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" /> <orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" />
<orderEntry type="library" name="Maven: com.googlecode.json-simple:json-simple:1.1.1" level="project" /> <orderEntry type="library" name="Maven: com.googlecode.json-simple:json-simple:1.1.1" level="project" />

View file

@ -1,4 +1,4 @@
import buttondevteam.component.updater.PluginUpdater; import buttondevteam.core.component.updater.PluginUpdater;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;

View file

@ -1,200 +1,200 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>com.github.TBMCPlugins</groupId> <groupId>com.github.TBMCPlugins</groupId>
<artifactId>ButtonCore</artifactId> <artifactId>ButtonCore</artifactId>
<version>master-SNAPSHOT</version> <version>master-SNAPSHOT</version>
</parent> </parent>
<groupId>com.github.TBMCPlugins.ButtonCore</groupId> <groupId>com.github.TBMCPlugins.ButtonCore</groupId>
<artifactId>ButtonCore</artifactId> <artifactId>ButtonCore</artifactId>
<name>ButtonCore</name> <name>ButtonCore</name>
<description>ButtonCore</description> <description>ButtonCore</description>
<build> <build>
<sourceDirectory>src/main/java</sourceDirectory> <sourceDirectory>src/main/java</sourceDirectory>
<resources> <resources>
<resource> <resource>
<directory>src/main/resources</directory> <directory>src/main/resources</directory>
<includes> <includes>
<include>*.properties</include> <include>*.properties</include>
<include>*.yml</include> <include>*.yml</include>
<include>*.csv</include> <include>*.csv</include>
<include>*.txt</include> <include>*.txt</include>
</includes> </includes>
<filtering>true</filtering> <filtering>true</filtering>
</resource> </resource>
</resources> </resources>
<finalName>ButtonCore</finalName> <finalName>ButtonCore</finalName>
<plugins> <plugins>
<plugin> <plugin>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<configuration> <configuration>
<source>1.8</source> <source>1.8</source>
<target>1.8</target> <target>1.8</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>2.4.2</version> <version>2.4.2</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
<goals> <goals>
<goal>shade</goal> <goal>shade</goal>
</goals> </goals>
<configuration> <configuration>
<artifactSet> <artifactSet>
</artifactSet> </artifactSet>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId> <artifactId>maven-resources-plugin</artifactId>
<version>3.0.1</version> <version>3.0.1</version>
<executions> <executions>
<execution> <execution>
<id>copy</id> <id>copy</id>
<phase>compile</phase> <phase>compile</phase>
<goals> <goals>
<goal>copy-resources</goal> <goal>copy-resources</goal>
</goals> </goals>
<configuration> <configuration>
<outputDirectory>target</outputDirectory> <outputDirectory>target</outputDirectory>
<resources> <resources>
<resource> <resource>
<directory>src/main/resources</directory> <directory>src/main/resources</directory>
</resource> </resource>
</resources> </resources>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<configuration> <configuration>
<useSystemClassLoader>false <useSystemClassLoader>false
</useSystemClassLoader> <!-- https://stackoverflow.com/a/53012553/2703239 --> </useSystemClassLoader> <!-- https://stackoverflow.com/a/53012553/2703239 -->
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
<executions> <executions>
<execution> <execution>
<id>attach-sources</id> <id>attach-sources</id>
<goals> <goals>
<goal>jar</goal> <goal>jar</goal>
</goals> </goals>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<repositories> <repositories>
<repository> <repository>
<id>spigot-repo</id> <id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url> <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository> </repository>
<repository> <repository>
<id>jitpack.io</id> <id>jitpack.io</id>
<url>https://jitpack.io/</url> <url>https://jitpack.io/</url>
</repository> </repository>
<repository> <repository>
<id>vault-repo</id> <id>vault-repo</id>
<url>http://nexus.hc.to/content/repositories/pub_releases</url> <url>http://nexus.hc.to/content/repositories/pub_releases</url>
</repository> </repository>
<repository> <repository>
<id>ess-repo</id> <id>ess-repo</id>
<url>http://repo.ess3.net/content/repositories/essrel/</url> <url>http://repo.ess3.net/content/repositories/essrel/</url>
</repository> </repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.reflections</groupId> <groupId>org.reflections</groupId>
<artifactId>reflections</artifactId> <artifactId>reflections</artifactId>
<version>0.9.10</version> <version>0.9.10</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId> <artifactId>spigot-api</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version> <version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-io --> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-io -->
<dependency> <dependency>
<groupId>commons-io</groupId> <groupId>commons-io</groupId>
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
<version>1.3.2</version> <version>1.3.2</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- Change jitpack.yml to set location of Towny JAR --> <!-- Change jitpack.yml to set location of Towny JAR -->
<dependency> <dependency>
<groupId>com.github.TBMCPlugins.ButtonCore</groupId> <groupId>com.github.TBMCPlugins.ButtonCore</groupId>
<artifactId>Towny</artifactId> <artifactId>Towny</artifactId>
<version>master-SNAPSHOT</version> <version>master-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.milkbowl</groupId> <!-- net.milkbowl.vault --> <groupId>com.github.milkbowl</groupId> <!-- net.milkbowl.vault -->
<artifactId>VaultAPI</artifactId> <artifactId>VaultAPI</artifactId>
<version>master-SNAPSHOT</version> <!-- 1.6 --> <version>master-SNAPSHOT</version> <!-- 1.6 -->
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.javassist/javassist --> <!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
<dependency> <dependency>
<groupId>org.javassist</groupId> <groupId>org.javassist</groupId>
<artifactId>javassist</artifactId> <artifactId>javassist</artifactId>
<version>3.20.0-GA</version> <version>3.20.0-GA</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId> <artifactId>mockito-core</artifactId>
<version>2.7.20</version> <version>2.7.20</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>1.16.16</version> <version>1.16.16</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.TBMCPlugins.ButtonCore</groupId> <groupId>com.github.TBMCPlugins.ButtonCore</groupId>
<artifactId>ButtonProcessor</artifactId> <artifactId>ButtonProcessor</artifactId>
<version>master-SNAPSHOT</version> <version>master-SNAPSHOT</version>
<scope>provided</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.ess3</groupId> <groupId>net.ess3</groupId>
<artifactId>Essentials</artifactId> <artifactId>Essentials</artifactId>
<version>2.13.1</version> <version>2.13.1</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<organization> <organization>
<name>TBMCPlugins</name> <name>TBMCPlugins</name>
<url>https://github.com/TBMCPlugins</url> <url>https://github.com/TBMCPlugins</url>
</organization> </organization>
<distributionManagement> <distributionManagement>
<repository> <repository>
<id>internal.repo</id> <id>internal.repo</id>
<name>Temporary Staging Repository</name> <name>Temporary Staging Repository</name>
<url>file://${project.build.directory}/mvn-repo/${project.name}</url> <url>file://${project.build.directory}/mvn-repo/${project.name}</url>
</repository> </repository>
</distributionManagement> </distributionManagement>
<properties> <properties>
<!-- github server corresponds to entry in ~/.m2/settings.xml --> <!-- github server corresponds to entry in ~/.m2/settings.xml -->
<github.global.server>github</github.global.server> <github.global.server>github</github.global.server>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
<scm> <scm>
<url>https://github.com/TBMCPlugins/mvn-repo</url> <url>https://github.com/TBMCPlugins/mvn-repo</url>
<connection>scm:git:https://github.com/TBMCPlugins/mvn-repo.git</connection> <connection>scm:git:https://github.com/TBMCPlugins/mvn-repo.git</connection>
<developerConnection>scm:git:https://github.com/TBMCPlugins/mvn-repo.git</developerConnection> <developerConnection>scm:git:https://github.com/TBMCPlugins/mvn-repo.git</developerConnection>
</scm> </scm>
</project> </project>

View file

@ -2,62 +2,65 @@ package buttondevteam.core;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.chat.Command2MC;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.TBMCCommandBase;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import java.util.Optional; import java.util.Optional;
@CommandClass(modOnly = true) @CommandClass(modOnly = true, helpText = {
public class ComponentCommand extends TBMCCommandBase { "§6---- Component command ----",
@Override "Can be used to enable/disable/list components"
public boolean OnCommand(CommandSender sender, String alias, String[] args) { })
if (args.length < 1) public class ComponentCommand extends Command2MC {
return false; public ComponentCommand() {
boolean enable = true; addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg));
}
@Subcommand
public boolean enable(CommandSender sender, Plugin plugin, String component) {
if (plugin == null) return respond(sender, "§cPlugin not found!");
plugin.reloadConfig(); //Reload config so the new config values are read - All changes are saved to disk on disable
return enable_disable(sender, plugin, component, true);
}
@Subcommand
public boolean disable(CommandSender sender, Plugin plugin, String component) {
if (plugin == null) return respond(sender, "§cPlugin not found!");
return enable_disable(sender, plugin, component, false);
}
@Subcommand
public boolean list(CommandSender sender, String plugin) {
sender.sendMessage("§6List of components:");
Component.getComponents().values().stream().filter(c -> plugin == null || c.getPlugin().getName().equalsIgnoreCase(plugin)) //If plugin is null, don't check
.map(c -> c.getPlugin().getName() + " - " + c.getClass().getSimpleName() + " - " + (c.isEnabled() ? "en" : "dis") + "abled").forEach(sender::sendMessage);
return true;
}
private boolean enable_disable(CommandSender sender, Plugin plugin, String component, boolean enable) {
try { try {
switch (args[0]) { val oc = getComponentOrError(plugin, component, sender);
case "enable":
enable = true;
break;
case "disable":
enable = false;
break;
case "list":
sender.sendMessage("§6List of components:");
Component.getComponents().values().stream().map(c -> c.getPlugin().getName() + " - " + c.getClass().getSimpleName() + " - " + (c.isEnabled() ? "en" : "dis") + "abled").forEach(sender::sendMessage);
return true;
default:
return false;
}
if (args.length < 2)
return false;
val oc = getComponentOrError(args[1], sender);
if (!oc.isPresent()) if (!oc.isPresent())
return true; return true;
if (enable) //Reload config so the new config values are read
getPlugin().reloadConfig(); //All changes are saved to disk on disable
Component.setComponentEnabled(oc.get(), enable); Component.setComponentEnabled(oc.get(), enable);
sender.sendMessage(oc.get().getClass().getSimpleName() + " " + (enable ? "en" : "dis") + "abled."); sender.sendMessage(oc.get().getClass().getSimpleName() + " " + (enable ? "en" : "dis") + "abled.");
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("Couldn't " + (enable ? "en" : "dis") + "able component " + args[0] + "!", e); TBMCCoreAPI.SendException("Couldn't " + (enable ? "en" : "dis") + "able component " + component + "!", e);
} }
return true; return true;
} }
private Optional<Component> getComponentOrError(String arg, CommandSender sender) { private Optional<Component> getComponentOrError(Plugin plugin, String arg, CommandSender sender) {
val oc = Component.getComponents().values().stream().filter(c -> c.getClass().getSimpleName().equalsIgnoreCase(arg)).findAny(); val oc = Component.getComponents().values().stream()
.filter(c -> plugin.getName().equals(c.getPlugin().getName()))
.filter(c -> c.getClass().getSimpleName().equalsIgnoreCase(arg)).findAny();
if (!oc.isPresent()) if (!oc.isPresent())
sender.sendMessage("§cComponent not found!"); sender.sendMessage("§cComponent not found!"); //^ Much simpler to solve in the new command system
return oc; return oc;
} } //TODO: Tabcompletion for the new command system
@Override
public String[] GetHelpText(String alias) {
return new String[]{
"§6---- Component command ----",
"Enable or disable or list components"
};
}
} }

View file

@ -1,6 +1,7 @@
package buttondevteam.core; package buttondevteam.core;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.ButtonPlugin;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import lombok.val; import lombok.val;
@ -31,16 +32,11 @@ public final class ComponentManager {
} }
/** /**
* Disables all components that are enabled * Unregister all components of a plugin that are enabled - called on {@link ButtonPlugin} disable
*/ */
public static void disableComponents() { public static void unregComponents(ButtonPlugin plugin) {
Component.getComponents().values().stream().filter(Component::isEnabled).forEach(c -> { while (!plugin.getComponentStack().empty()) //Unregister in reverse order
try { Component.unregisterComponent(plugin, plugin.getComponentStack().pop()); //Components are pushed on register
Component.setComponentEnabled(c, false);
} catch (Exception e) {
TBMCCoreAPI.SendException("Failed to disable one of the components: " + c.getClass().getSimpleName(), e);
}
});
componentsEnabled = false; componentsEnabled = false;
} }
@ -54,4 +50,16 @@ public final class ComponentManager {
val c = Component.getComponents().get(cl); val c = Component.getComponents().get(cl);
return c != null && c.isEnabled(); return c != null && c.isEnabled();
} }
/**
* Will also return null if the component is not registered.
*
* @param cl The component class
* @return The component if it's registered and enabled
*/
@SuppressWarnings("unchecked")
public static <T extends Component> T getIfEnabled(Class<T> cl) {
val c = Component.getComponents().get(cl);
return c != null && c.isEnabled() ? (T) c : null;
}
} }

View file

@ -1,19 +1,20 @@
package buttondevteam.core; package buttondevteam.core;
import buttondevteam.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.component.channel.ChannelComponent; import buttondevteam.core.component.channel.ChannelComponent;
import buttondevteam.component.channel.ChatRoom; import buttondevteam.core.component.channel.ChatRoom;
import buttondevteam.component.members.MemberComponent; import buttondevteam.core.component.members.MemberComponent;
import buttondevteam.component.randomtp.RandomTPComponent; import buttondevteam.core.component.randomtp.RandomTPComponent;
import buttondevteam.component.restart.RestartComponent; import buttondevteam.core.component.restart.RestartComponent;
import buttondevteam.component.towny.TownyComponent; import buttondevteam.core.component.towny.TownyComponent;
import buttondevteam.component.updater.PluginUpdater; import buttondevteam.core.component.updater.PluginUpdater;
import buttondevteam.component.updater.PluginUpdaterComponent; import buttondevteam.core.component.updater.PluginUpdaterComponent;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.ButtonPlugin;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.architecture.ConfigData;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Color;
import buttondevteam.lib.chat.Command2MC;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayer;
@ -68,7 +69,7 @@ public class MainPlugin extends ButtonPlugin {
Component.registerComponent(this, new MemberComponent()); Component.registerComponent(this, new MemberComponent());
Component.registerComponent(this, new TownyComponent()); Component.registerComponent(this, new TownyComponent());
ComponentManager.enableComponents(); ComponentManager.enableComponents();
TBMCChatAPI.AddCommand(this, ComponentCommand.class); Command2MC.registerCommand(new ComponentCommand());
TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this); TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this);
ChromaGamerBase.addConverter(commandSender -> Optional.ofNullable(commandSender instanceof ConsoleCommandSender || commandSender instanceof BlockCommandSender ChromaGamerBase.addConverter(commandSender -> Optional.ofNullable(commandSender instanceof ConsoleCommandSender || commandSender instanceof BlockCommandSender
? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks ? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks
@ -100,7 +101,6 @@ public class MainPlugin extends ButtonPlugin {
@Override @Override
public void pluginDisable() { public void pluginDisable() {
ComponentManager.disableComponents();
logger.info("Saving player data..."); logger.info("Saving player data...");
TBMCPlayerBase.savePlayers(); TBMCPlayerBase.savePlayers();
logger.info("Player data saved."); logger.info("Player data saved.");
@ -132,6 +132,7 @@ public class MainPlugin extends ButtonPlugin {
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (command.getName().equals("dontrunthiscmd")) return true; //Used in chat preprocess for console
sender.sendMessage("§cThis command isn't available."); //In theory, unregistered commands use this method sender.sendMessage("§cThis command isn't available."); //In theory, unregistered commands use this method
return true; return true;
} }

View file

@ -1,13 +1,21 @@
package buttondevteam.core; package buttondevteam.core;
import buttondevteam.lib.TBMCCommandPreprocessEvent;
import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.TBMCSystemChatEvent;
import buttondevteam.lib.chat.Command2MC;
import buttondevteam.lib.player.TBMCPlayerBase; import buttondevteam.lib.player.TBMCPlayerBase;
import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.ServerCommandEvent;
import java.util.Arrays; import java.util.Arrays;
@ -32,4 +40,33 @@ public class PlayerListener implements Listener {
Bukkit.getOnlinePlayers().stream().filter(event::shouldSendTo) Bukkit.getOnlinePlayers().stream().filter(event::shouldSendTo)
.forEach(p -> p.sendMessage(event.getChannel().DisplayName().get().substring(0, 2) + event.getMessage())); .forEach(p -> p.sendMessage(event.getChannel().DisplayName().get().substring(0, 2) + event.getMessage()));
} }
@EventHandler
public void onPlayerChatPreprocess(PlayerCommandPreprocessEvent event) {
handlePreprocess(event.getPlayer(), event.getMessage(), event);
}
@EventHandler
public void onSystemChatPreprocess(ServerCommandEvent event) {
handlePreprocess(event.getSender(), "/" + event.getCommand(), event);
if (event.isCancelled()) event.setCommand("dontrunthiscmd"); //Bugfix
}
private void handlePreprocess(CommandSender sender, String message, Cancellable event) {
if (event.isCancelled()) return;
val ev = new TBMCCommandPreprocessEvent(sender, message);
Bukkit.getPluginManager().callEvent(ev);
if (ev.isCancelled())
event.setCancelled(true); //Cancel the original event
}
@EventHandler
public void onTBMCPreprocess(TBMCCommandPreprocessEvent event) {
if (event.isCancelled()) return;
try {
event.setCancelled(Command2MC.handleCommand(event.getSender(), event.getMessage()));
} catch (Exception e) {
TBMCCoreAPI.SendException("Command processing failed for sender '" + event.getSender() + "' and message '" + event.getMessage() + "'", e);
}
}
} }

View file

@ -1,13 +1,14 @@
package buttondevteam.core; package buttondevteam.core;
import buttondevteam.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.component.channel.ChannelComponent; import buttondevteam.core.component.channel.ChannelComponent;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Color;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitScheduler;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
@ -40,7 +41,7 @@ public class TestPrepare {
return cl.isAssignableFrom(invocation.getMethod().getReturnType()); return cl.isAssignableFrom(invocation.getMethod().getReturnType());
} }
})); }));
Component.registerComponent(Mockito.mock(MainPlugin.class), new ChannelComponent()); Component.registerComponent(Mockito.mock(JavaPlugin.class), new ChannelComponent());
TBMCChatAPI.RegisterChatChannel(Channel.GlobalChat = new Channel("§fg§f", Color.White, "g", null)); TBMCChatAPI.RegisterChatChannel(Channel.GlobalChat = new Channel("§fg§f", Color.White, "g", null));
} }
} }

View file

@ -1,4 +1,4 @@
package buttondevteam.component.channel; package buttondevteam.core.component.channel;
import buttondevteam.core.ComponentManager; import buttondevteam.core.ComponentManager;
import buttondevteam.core.MainPlugin; import buttondevteam.core.MainPlugin;

View file

@ -1,4 +1,4 @@
package buttondevteam.component.channel; package buttondevteam.core.component.channel;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;

View file

@ -1,4 +1,4 @@
package buttondevteam.component.channel; package buttondevteam.core.component.channel;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;

View file

@ -1,4 +1,4 @@
package buttondevteam.component.channel; package buttondevteam.core.component.channel;
import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.Color;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;

View file

@ -1,4 +1,4 @@
package buttondevteam.component.members; package buttondevteam.core.component.members;
import buttondevteam.core.MainPlugin; import buttondevteam.core.MainPlugin;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;

View file

@ -1,4 +1,4 @@
package buttondevteam.component.members; package buttondevteam.core.component.members;
import buttondevteam.core.MainPlugin; import buttondevteam.core.MainPlugin;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;

View file

@ -1,4 +1,4 @@
package buttondevteam.component.randomtp; package buttondevteam.core.component.randomtp;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;

View file

@ -1,4 +1,4 @@
package buttondevteam.component.randomtp; package buttondevteam.core.component.randomtp;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;

View file

@ -1,4 +1,4 @@
package buttondevteam.component.restart; package buttondevteam.core.component.restart;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.TBMCCommandBase; import buttondevteam.lib.chat.TBMCCommandBase;

View file

@ -1,4 +1,4 @@
package buttondevteam.component.restart; package buttondevteam.core.component.restart;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.chat.IFakePlayer; import buttondevteam.lib.chat.IFakePlayer;

View file

@ -1,9 +1,11 @@
package buttondevteam.component.restart; package buttondevteam.core.component.restart;
import buttondevteam.core.MainPlugin; import buttondevteam.core.MainPlugin;
import buttondevteam.lib.ScheduledServerRestartEvent; import buttondevteam.lib.ScheduledServerRestartEvent;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.TBMCCommandBase; import buttondevteam.lib.chat.TBMCCommandBase;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.boss.BarColor; import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarFlag; import org.bukkit.boss.BarFlag;
@ -14,43 +16,45 @@ import org.bukkit.scheduler.BukkitTask;
@CommandClass(modOnly = true, path = "schrestart") @CommandClass(modOnly = true, path = "schrestart")
public class ScheduledRestartCommand extends TBMCCommandBase { public class ScheduledRestartCommand extends TBMCCommandBase {
private static volatile int restartcounter; @Getter
private static volatile BukkitTask restarttask; @Setter
private static volatile BossBar restartbar; private int restartCounter;
private BukkitTask restarttask;
private volatile BossBar restartbar;
@Override @Override
public boolean OnCommand(CommandSender sender, String alias, String[] args) { public boolean OnCommand(CommandSender sender, String alias, String[] args) {
int ticks = 20 * 60; int secs = 60;
try { try {
if (args.length > 0) if (args.length > 0)
ticks = Integer.parseInt(args[0]); secs = Integer.parseInt(args[0]);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
sender.sendMessage("§cError: Ticks must be a number."); sender.sendMessage("§cError: Seconds must be a number.");
return false; return false;
} }
if (ticks < 20) { if (secs < 10) {
sender.sendMessage("§cError: Ticks must be more than 20."); sender.sendMessage("§cError: Seconds must be at least 10.");
return false; return false;
} }
final int restarttime = restartcounter = ticks; final int restarttime = restartCounter = secs * 20;
restartbar = Bukkit.createBossBar("Server restart in " + ticks / 20f + "s", BarColor.RED, BarStyle.SOLID, restartbar = Bukkit.createBossBar("Server restart in " + secs + "s", BarColor.RED, BarStyle.SOLID,
BarFlag.DARKEN_SKY); BarFlag.DARKEN_SKY);
restartbar.setProgress(1); restartbar.setProgress(1);
Bukkit.getOnlinePlayers().forEach(p -> restartbar.addPlayer(p)); Bukkit.getOnlinePlayers().forEach(p -> restartbar.addPlayer(p));
sender.sendMessage("Scheduled restart in " + ticks / 20f); sender.sendMessage("Scheduled restart in " + secs);
ScheduledServerRestartEvent e = new ScheduledServerRestartEvent(ticks); ScheduledServerRestartEvent e = new ScheduledServerRestartEvent(restarttime, this);
Bukkit.getPluginManager().callEvent(e); Bukkit.getPluginManager().callEvent(e);
restarttask = Bukkit.getScheduler().runTaskTimer(MainPlugin.Instance, () -> { restarttask = Bukkit.getScheduler().runTaskTimer(MainPlugin.Instance, () -> {
if (restartcounter < 0) { if (restartCounter < 0) {
restarttask.cancel(); restarttask.cancel();
restartbar.getPlayers().forEach(p -> restartbar.removePlayer(p)); restartbar.getPlayers().forEach(p -> restartbar.removePlayer(p));
Bukkit.spigot().restart(); Bukkit.spigot().restart();
} }
if (restartcounter % 200 == 0) if (restartCounter % 200 == 0)
Bukkit.broadcastMessage("§c-- The server is restarting in " + restartcounter / 20 + " seconds!"); Bukkit.broadcastMessage("§c-- The server is restarting in " + restartCounter / 20 + " seconds! (/press)");
restartbar.setProgress(restartcounter / (double) restarttime); restartbar.setProgress(restartCounter / (double) restarttime);
restartbar.setTitle(String.format("Server restart in %.2f", restartcounter / 20f)); restartbar.setTitle(String.format("Server restart in %.2f", restartCounter / 20f));
restartcounter--; restartCounter--;
}, 1, 1); }, 1, 1);
return true; return true;
} }

View file

@ -1,4 +1,4 @@
package buttondevteam.component.towny; package buttondevteam.core.component.towny;
import buttondevteam.core.ComponentManager; import buttondevteam.core.ComponentManager;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;

View file

@ -1,4 +1,4 @@
package buttondevteam.component.updater; package buttondevteam.core.component.updater;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;

View file

@ -1,4 +1,4 @@
package buttondevteam.component.updater; package buttondevteam.core.component.updater;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;

View file

@ -1,4 +1,4 @@
package buttondevteam.component.updater; package buttondevteam.core.component.updater;
import buttondevteam.core.MainPlugin; import buttondevteam.core.MainPlugin;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;

View file

@ -1,20 +1,18 @@
package buttondevteam.lib; package buttondevteam.lib;
import buttondevteam.core.component.restart.ScheduledRestartCommand;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
@Getter
@RequiredArgsConstructor
public class ScheduledServerRestartEvent extends Event { public class ScheduledServerRestartEvent extends Event {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private final int restartticks; private final int restartTicks;
private final ScheduledRestartCommand command;
public ScheduledServerRestartEvent(int restartticks) {
this.restartticks = restartticks;
}
public int getRestartTicks() {
return restartticks;
}
@Override @Override
public HandlerList getHandlers() { public HandlerList getHandlers() {

View file

@ -1,6 +1,6 @@
package buttondevteam.lib; package buttondevteam.lib;
import buttondevteam.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.ChatMessage;
import lombok.Getter; import lombok.Getter;
import lombok.experimental.Delegate; import lombok.experimental.Delegate;

View file

@ -1,6 +1,6 @@
package buttondevteam.lib; package buttondevteam.lib;
import buttondevteam.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;

View file

@ -1,6 +1,6 @@
package buttondevteam.lib; package buttondevteam.lib;
import buttondevteam.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;

View file

@ -0,0 +1,39 @@
package buttondevteam.lib;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
/**
* Can be used to change or handle commands before they're sent.
* <b>Called on using player, console and Discord commands.</b>
*
* @author NorbiPeti
*/
@Getter
public class TBMCCommandPreprocessEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private final CommandSender sender;
@Setter
private String message;
@Setter
private boolean cancelled;
public TBMCCommandPreprocessEvent(CommandSender sender, String message) {
this.sender = sender;
this.message = message; //TODO: Actually call from Discord as well
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
}

View file

@ -1,188 +1,188 @@
package buttondevteam.lib; package buttondevteam.lib;
import buttondevteam.component.updater.PluginUpdater; import buttondevteam.core.MainPlugin;
import buttondevteam.core.MainPlugin; import buttondevteam.core.component.updater.PluginUpdater;
import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.ChromaGamerBase;
import buttondevteam.lib.potato.DebugPotato; import buttondevteam.lib.potato.DebugPotato;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
public class TBMCCoreAPI { public class TBMCCoreAPI {
static final List<String> coders = new ArrayList<String>() { static final List<String> coders = new ArrayList<String>() {
private static final long serialVersionUID = -4462159250738367334L; private static final long serialVersionUID = -4462159250738367334L;
{ {
add("Alisolarflare"); add("Alisolarflare");
add("NorbiPeti"); add("NorbiPeti");
add("iie"); add("iie");
add("thewindmillman"); add("thewindmillman");
add("mayskam1995"); add("mayskam1995");
} }
}; };
/** /**
* Updates or installs the specified plugin. The plugin must use Maven. * Updates or installs the specified plugin. The plugin must use Maven.
* *
* @param name * @param name
* The plugin's repository name. * The plugin's repository name.
* @param sender * @param sender
* The command sender (if not console, messages will be printed to console as well). * The command sender (if not console, messages will be printed to console as well).
*/ */
public static void UpdatePlugin(String name, CommandSender sender) { public static void UpdatePlugin(String name, CommandSender sender) {
UpdatePlugin(name, sender, "master"); UpdatePlugin(name, sender, "master");
} }
/** /**
* Updates or installs the specified plugin from the specified branch. The plugin must use Maven. * Updates or installs the specified plugin from the specified branch. The plugin must use Maven.
* *
* @param name * @param name
* The plugin's repository name. * The plugin's repository name.
* @param sender * @param sender
* The command sender (if not console, messages will be printed to console as well). * The command sender (if not console, messages will be printed to console as well).
* @param branch * @param branch
* The branch to download the plugin from. * The branch to download the plugin from.
* @return Success or not * @return Success or not
*/ */
public static boolean UpdatePlugin(String name, CommandSender sender, String branch) { public static boolean UpdatePlugin(String name, CommandSender sender, String branch) {
return PluginUpdater.UpdatePlugin(name, sender, branch); return PluginUpdater.UpdatePlugin(name, sender, branch);
} }
public static String DownloadString(String urlstr) throws IOException { public static String DownloadString(String urlstr) throws IOException {
URL url = new URL(urlstr); URL url = new URL(urlstr);
URLConnection con = url.openConnection(); URLConnection con = url.openConnection();
con.setRequestProperty("User-Agent", "TBMCPlugins"); con.setRequestProperty("User-Agent", "TBMCPlugins");
InputStream in = con.getInputStream(); InputStream in = con.getInputStream();
String encoding = con.getContentEncoding(); String encoding = con.getContentEncoding();
encoding = encoding == null ? "UTF-8" : encoding; encoding = encoding == null ? "UTF-8" : encoding;
String body = IOUtils.toString(in, encoding); String body = IOUtils.toString(in, encoding);
in.close(); in.close();
return body; return body;
} }
private static final HashMap<String, Throwable> exceptionsToSend = new HashMap<>(); private static final HashMap<String, Throwable> exceptionsToSend = new HashMap<>();
private static final List<String> debugMessagesToSend = new ArrayList<>(); private static final List<String> debugMessagesToSend = new ArrayList<>();
/** /**
* Send exception to the {@link TBMCExceptionEvent}. * Send exception to the {@link TBMCExceptionEvent}.
* *
* @param sourcemsg * @param sourcemsg
* A message that is shown at the top of the exception (before the exception's message) * A message that is shown at the top of the exception (before the exception's message)
* @param e * @param e
* The exception to send * The exception to send
*/ */
public static void SendException(String sourcemsg, Throwable e) { public static void SendException(String sourcemsg, Throwable e) {
SendException(sourcemsg, e, false); SendException(sourcemsg, e, false);
} }
public static void SendException(String sourcemsg, Throwable e, boolean debugPotato) { public static void SendException(String sourcemsg, Throwable e, boolean debugPotato) {
SendUnsentExceptions(); SendUnsentExceptions();
TBMCExceptionEvent event = new TBMCExceptionEvent(sourcemsg, e); TBMCExceptionEvent event = new TBMCExceptionEvent(sourcemsg, e);
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
synchronized (exceptionsToSend) { synchronized (exceptionsToSend) {
if (!event.isHandled()) if (!event.isHandled())
exceptionsToSend.put(sourcemsg, e); exceptionsToSend.put(sourcemsg, e);
} }
Bukkit.getLogger().warning(sourcemsg); Bukkit.getLogger().warning(sourcemsg);
e.printStackTrace(); e.printStackTrace();
if (debugPotato) { if (debugPotato) {
List<Player> devsOnline = new ArrayList<Player>(); List<Player> devsOnline = new ArrayList<Player>();
for (Player player : Bukkit.getOnlinePlayers()) { for (Player player : Bukkit.getOnlinePlayers()) {
if (coders.contains(player.getName())) { if (coders.contains(player.getName())) {
devsOnline.add(player); devsOnline.add(player);
} }
} }
if (!devsOnline.isEmpty()) { if (!devsOnline.isEmpty()) {
DebugPotato potato = new DebugPotato() DebugPotato potato = new DebugPotato()
.setMessage(new String[] { // .setMessage(new String[] { //
"§b§o" + e.getClass().getSimpleName(), // "§b§o" + e.getClass().getSimpleName(), //
"§c§o" + sourcemsg, // "§c§o" + sourcemsg, //
"§a§oFind a dev to fix this issue" }) "§a§oFind a dev to fix this issue" })
.setType(e instanceof IOException ? "Throwable Potato" .setType(e instanceof IOException ? "Throwable Potato"
: e instanceof ClassCastException ? "Squished Potato" : e instanceof ClassCastException ? "Squished Potato"
: e instanceof NullPointerException ? "Plain Potato" : e instanceof NullPointerException ? "Plain Potato"
: e instanceof StackOverflowError ? "Chips" : "Error Potato"); : e instanceof StackOverflowError ? "Chips" : "Error Potato");
for (Player dev : devsOnline) { for (Player dev : devsOnline) {
potato.Send(dev); potato.Send(dev);
} }
} }
} }
} }
public static void sendDebugMessage(String debugMessage) { public static void sendDebugMessage(String debugMessage) {
SendUnsentDebugMessages(); SendUnsentDebugMessages();
TBMCDebugMessageEvent event = new TBMCDebugMessageEvent(debugMessage); TBMCDebugMessageEvent event = new TBMCDebugMessageEvent(debugMessage);
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
synchronized (debugMessagesToSend) { synchronized (debugMessagesToSend) {
if (!event.isSent()) if (!event.isSent())
debugMessagesToSend.add(debugMessage); debugMessagesToSend.add(debugMessage);
} }
} }
/** /**
* Registers Bukkit events, handling the exceptions occurring in those events * Registers Bukkit events, handling the exceptions occurring in those events
* *
* @param listener * @param listener
* The class that handles the events * The class that handles the events
* @param plugin * @param plugin
* The plugin which the listener belongs to * The plugin which the listener belongs to
*/ */
public static void RegisterEventsForExceptions(Listener listener, Plugin plugin) { public static void RegisterEventsForExceptions(Listener listener, Plugin plugin) {
EventExceptionHandler.registerEvents(listener, plugin, new EventExceptionCoreHandler()); EventExceptionHandler.registerEvents(listener, plugin, new EventExceptionCoreHandler());
} }
public static <T extends ChromaGamerBase> void RegisterUserClass(Class<T> userclass) { public static <T extends ChromaGamerBase> void RegisterUserClass(Class<T> userclass) {
ChromaGamerBase.RegisterPluginUserClass(userclass); ChromaGamerBase.RegisterPluginUserClass(userclass);
} }
/** /**
* Send exceptions that haven't been sent (their events didn't get handled). This method is used by the DiscordPlugin's ready event * Send exceptions that haven't been sent (their events didn't get handled). This method is used by the DiscordPlugin's ready event
*/ */
public static void SendUnsentExceptions() { public static void SendUnsentExceptions() {
synchronized (exceptionsToSend) { synchronized (exceptionsToSend) {
if (exceptionsToSend.size() > 20) { if (exceptionsToSend.size() > 20) {
exceptionsToSend.clear(); // Don't call more and more events if all the handler plugins are unloaded exceptionsToSend.clear(); // Don't call more and more events if all the handler plugins are unloaded
Bukkit.getLogger().warning("Unhandled exception list is over 20! Clearing!"); Bukkit.getLogger().warning("Unhandled exception list is over 20! Clearing!");
} }
for (Iterator<Entry<String, Throwable>> iterator = exceptionsToSend.entrySet().iterator(); iterator.hasNext(); ) { for (Iterator<Entry<String, Throwable>> iterator = exceptionsToSend.entrySet().iterator(); iterator.hasNext(); ) {
Entry<String, Throwable> entry = iterator.next(); Entry<String, Throwable> entry = iterator.next();
TBMCExceptionEvent event = new TBMCExceptionEvent(entry.getKey(), entry.getValue()); TBMCExceptionEvent event = new TBMCExceptionEvent(entry.getKey(), entry.getValue());
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
if (event.isHandled()) if (event.isHandled())
iterator.remove(); iterator.remove();
} }
} }
} }
public static void SendUnsentDebugMessages() { public static void SendUnsentDebugMessages() {
synchronized (debugMessagesToSend) { synchronized (debugMessagesToSend) {
if (debugMessagesToSend.size() > 20) { if (debugMessagesToSend.size() > 20) {
debugMessagesToSend.clear(); // Don't call more and more DebugMessages if all the handler plugins are unloaded debugMessagesToSend.clear(); // Don't call more and more DebugMessages if all the handler plugins are unloaded
Bukkit.getLogger().warning("Unhandled Debug Message list is over 20! Clearing!"); Bukkit.getLogger().warning("Unhandled Debug Message list is over 20! Clearing!");
} }
for (Iterator<String> iterator = debugMessagesToSend.iterator(); iterator.hasNext(); ) { for (Iterator<String> iterator = debugMessagesToSend.iterator(); iterator.hasNext(); ) {
String message = iterator.next(); String message = iterator.next();
TBMCDebugMessageEvent event = new TBMCDebugMessageEvent(message); TBMCDebugMessageEvent event = new TBMCDebugMessageEvent(message);
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
if (event.isSent()) if (event.isSent())
iterator.remove(); iterator.remove();
} }
} }
} }
public static boolean IsTestServer() { public static boolean IsTestServer() {
return MainPlugin.Test; return MainPlugin.Test;
} }
} }

View file

@ -1,6 +1,6 @@
package buttondevteam.lib; package buttondevteam.lib;
import buttondevteam.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import lombok.Getter; import lombok.Getter;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;

View file

@ -0,0 +1,38 @@
package buttondevteam.lib;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public final class ThorpeUtils {
private ThorpeUtils() {}
public static String getDisplayName(CommandSender sender) {
if (sender instanceof IHaveFancyName)
return ((IHaveFancyName) sender).getFancyName();
if (sender instanceof Player)
return ((Player) sender).getDisplayName();
return sender.getName();
}
public static String getFullDisplayName(CommandSender sender) {
if (sender instanceof IHaveFancyName)
return ((IHaveFancyName) sender).getFancyFullName();
return getDisplayName(sender);
}
public interface IHaveFancyName {
/**
* May not be null.
*
* @return The name to be displayed in most places.
*/
String getFancyName();
/**
* May return null.
*
* @return The full name that can be used to uniquely indentify the user.
*/
String getFancyFullName();
}
}

View file

@ -1,5 +1,6 @@
package buttondevteam.lib.architecture; package buttondevteam.lib.architecture;
import buttondevteam.core.ComponentManager;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import lombok.AccessLevel; import lombok.AccessLevel;
@ -7,14 +8,30 @@ import lombok.Getter;
import lombok.experimental.var; import lombok.experimental.var;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import java.util.Stack;
public abstract class ButtonPlugin extends JavaPlugin { public abstract class ButtonPlugin extends JavaPlugin {
@Getter(AccessLevel.PROTECTED) @Getter(AccessLevel.PROTECTED)
private IHaveConfig iConfig; private IHaveConfig iConfig;
/**
* Used to unregister components in the right order
*/
@Getter
private Stack<Component> componentStack = new Stack<>();
protected abstract void pluginEnable(); protected abstract void pluginEnable();
/**
* Called after the components are unregistered
*/
protected abstract void pluginDisable(); protected abstract void pluginDisable();
/**
* Called before the components are unregistered
*/
protected void pluginPreDisable() {
}
@Override @Override
public final void onEnable() { public final void onEnable() {
var section = super.getConfig().getConfigurationSection("global"); var section = super.getConfig().getConfigurationSection("global");
@ -30,6 +47,8 @@ public abstract class ButtonPlugin extends JavaPlugin {
@Override @Override
public final void onDisable() { public final void onDisable() {
try { try {
pluginPreDisable();
ComponentManager.unregComponents(this);
pluginDisable(); pluginDisable();
saveConfig(); saveConfig();
iConfig = null; //Clearing the hashmap is not enough, we need to update the section as well iConfig = null; //Clearing the hashmap is not enough, we need to update the section as well

View file

@ -3,6 +3,7 @@ package buttondevteam.lib.architecture;
import buttondevteam.core.ComponentManager; import buttondevteam.core.ComponentManager;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.exceptions.UnregisteredComponentException; import buttondevteam.lib.architecture.exceptions.UnregisteredComponentException;
import buttondevteam.lib.chat.Command2MC;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.chat.TBMCCommandBase; import buttondevteam.lib.chat.TBMCCommandBase;
import lombok.Getter; import lombok.Getter;
@ -38,7 +39,8 @@ public abstract class Component {
/** /**
* Registers a component checking it's dependencies and calling {@link #register(JavaPlugin)}.<br> * Registers a component checking it's dependencies and calling {@link #register(JavaPlugin)}.<br>
* Make sure to register the dependencies first.<br> * Make sure to register the dependencies first.<br>
* The component will be enabled automatically, regardless of when it was registered. * The component will be enabled automatically, regardless of when it was registered.<br>
* <b>If not using {@link ButtonPlugin}, call {@link ComponentManager#unregComponents(ButtonPlugin)} on plugin disable.</b>
* *
* @param component The component to register * @param component The component to register
* @return Whether the component is registered successfully (it may have failed to enable) * @return Whether the component is registered successfully (it may have failed to enable)
@ -49,15 +51,13 @@ public abstract class Component {
/** /**
* Unregisters a component by calling {@link #unregister(JavaPlugin)}.<br> * Unregisters a component by calling {@link #unregister(JavaPlugin)}.<br>
* Make sure to unregister the dependencies last. * Make sure to unregister the dependencies last.<br>
* <b>Components will be unregistered in opposite order of registering by default by {@link ButtonPlugin} or {@link ComponentManager#unregComponents(ButtonPlugin)}.</b>
* *
* @param componentClass The component class to unregister * @param component The component to unregister
* @return Whether the component is unregistered successfully (it also got disabled) * @return Whether the component is unregistered successfully (it also got disabled)
*/ */
public static boolean unregisterComponent(JavaPlugin plugin, Class<? extends Component> componentClass) { public static boolean unregisterComponent(JavaPlugin plugin, Component component) {
val component = components.get(componentClass);
if (component == null)
return false; //Failed to load
return registerUnregisterComponent(plugin, component, false); return registerUnregisterComponent(plugin, component, false);
} }
@ -74,10 +74,16 @@ public abstract class Component {
} }
} }
if (register) { if (register) {
if (components.containsKey(component.getClass())) {
TBMCCoreAPI.SendException("Failed to register component " + component.getClassName(), new IllegalArgumentException("The component is already registered!"));
return false;
}
component.plugin = plugin; component.plugin = plugin;
updateConfig(plugin, component); updateConfig(plugin, component);
component.register(plugin); component.register(plugin);
components.put(component.getClass(), component); components.put(component.getClass(), component);
if (plugin instanceof ButtonPlugin)
((ButtonPlugin) plugin).getComponentStack().push(component);
if (ComponentManager.areComponentsEnabled() && component.shouldBeEnabled().get()) { if (ComponentManager.areComponentsEnabled() && component.shouldBeEnabled().get()) {
try { //Enable components registered after the previous ones getting enabled try { //Enable components registered after the previous ones getting enabled
setComponentEnabled(component, true); setComponentEnabled(component, true);
@ -89,6 +95,8 @@ public abstract class Component {
} }
return true; //Component shouldn't be enabled return true; //Component shouldn't be enabled
} else { } else {
if (!components.containsKey(component.getClass()))
return true; //Already unregistered
if (component.enabled) { if (component.enabled) {
try { try {
setComponentEnabled(component, false); setComponentEnabled(component, false);
@ -183,6 +191,16 @@ public abstract class Component {
*/ */
protected abstract void disable(); protected abstract void disable();
/**
* Registers a TBMCCommand to the component. Make sure to use {@link buttondevteam.lib.chat.CommandClass} and {@link buttondevteam.lib.chat.Command2.Subcommand}.
* You don't need to register the command in plugin.yml.
*
* @param commandBase Custom coded command class
*/
protected final void registerCommand(Command2MC commandBase) {
Command2MC.registerCommand(commandBase);
}
/** /**
* Registers a TBMCCommand to the component. Make sure to add it to plugin.yml and use {@link buttondevteam.lib.chat.CommandClass}. * Registers a TBMCCommand to the component. Make sure to add it to plugin.yml and use {@link buttondevteam.lib.chat.CommandClass}.
* *

View file

@ -62,6 +62,18 @@ public class ConfigData<T> { //TODO: Save after a while
if (hmm == null) hmm = def; //Set if the getter returned null if (hmm == null) hmm = def; //Set if the getter returned null
return hmm; return hmm;
} }
if (val instanceof Number) {
if (def instanceof Long)
val = ((Number) val).longValue();
else if (def instanceof Short)
val = ((Number) val).shortValue();
else if (def instanceof Byte)
val = ((Number) val).byteValue();
else if (def instanceof Float)
val = ((Number) val).floatValue();
else if (def instanceof Double)
val = ((Number) val).doubleValue();
}
return (T) val; return (T) val;
} }

View file

@ -1,13 +1,15 @@
package buttondevteam.lib.architecture; package buttondevteam.lib.architecture;
import lombok.Getter; import lombok.Getter;
import lombok.val;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import java.util.HashMap; import java.util.HashMap;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier;
/** /**
* Members of this interface should be protected (access level) * A config system
*/ */
public final class IHaveConfig { public final class IHaveConfig {
private final HashMap<String, ConfigData<?>> datamap = new HashMap<>(); private final HashMap<String, ConfigData<?>> datamap = new HashMap<>();
@ -15,7 +17,7 @@ public final class IHaveConfig {
private ConfigurationSection config; private ConfigurationSection config;
/** /**
* May be used in testing * May be used in testing.
* *
* @param section May be null for testing * @param section May be null for testing
*/ */
@ -73,4 +75,42 @@ public final class IHaveConfig {
datamap.put(path, data = new ConfigData<>(config, path, getter.apply(primitiveDef), primitiveDef, getter, setter)); datamap.put(path, data = new ConfigData<>(config, path, getter.apply(primitiveDef), primitiveDef, getter, setter));
return (ConfigData<T>) data; return (ConfigData<T>) data;
} }
/**
* This method overload should only be used with primitves or String.
*
* @param path The path in config to use
* @param def The value to use by default
* @param <T> The type of this variable (only use primitives or String)
* @return The data object that can be used to get or set the value
*/
@SuppressWarnings("unchecked")
public <T> ConfigData<T> getData(String path, Supplier<T> def) {
ConfigData<?> data = datamap.get(path);
if (data == null) {
val defval = def.get();
datamap.put(path, data = new ConfigData<>(config, path, defval, defval));
}
return (ConfigData<T>) data;
}
/**
* This method overload may be used with any class.
*
* @param path The path in config to use
* @param def The value to use by default
* @param getter A function that converts a primitive representation to the correct value
* @param setter A function that converts a value to a primitive representation
* @param <T> The type of this variable (can be any class)
* @return The data object that can be used to get or set the value
*/
@SuppressWarnings("unchecked")
public <T> ConfigData<T> getData(String path, Supplier<T> def, Function<Object, T> getter, Function<T, Object> setter) {
ConfigData<?> data = datamap.get(path);
if (data == null) {
val defval = def.get();
datamap.put(path, data = new ConfigData<>(config, path, defval, setter.apply(defval), getter, setter));
}
return (ConfigData<T>) data;
}
} }

View file

@ -1,25 +1,53 @@
package buttondevteam.lib.chat; package buttondevteam.lib.chat;
import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.player.ChromaGamerBase;
import lombok.RequiredArgsConstructor;
import lombok.experimental.var;
import lombok.val;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.InputStreamReader;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* The method name is the subcommand, use underlines (_) to add further subcommands.
* The args may be null if the conversion failed.
*/
public abstract class Command2 { public abstract class Command2 {
/** /**
* Default handler for commands, can be used to copy the args too. * Default handler for commands, can be used to copy the args too.
* *
* @param sender The sender which ran the command * @param sender The sender which ran the command
* @param command The (sub)command ran by the user
* @param args All of the arguments passed as is * @param args All of the arguments passed as is
* @return * @return The success of the command
*/ */
public boolean def(CommandSender sender, String command, @TextArg String args) { public boolean def(CommandSender sender, @TextArg String args) {
return false; return false;
} }
/**
* Convenience method. Return with this.
*
* @param sender The sender of the command
* @param message The message to send to the sender
* @return Always true so that the usage isn't shown
*/
protected boolean respond(CommandSender sender, String message) {
sender.sendMessage(message);
return true;
}
/** /**
* TODO: @CommandClass(helpText=...) * TODO: @CommandClass(helpText=...)
* Parameters annotated with this receive all of the remaining arguments * Parameters annotated with this receive all of the remaining arguments
@ -28,4 +56,172 @@ public abstract class Command2 {
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface TextArg { public @interface TextArg {
} }
}
/**
* Methods annotated with this will be recognised as subcommands
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Subcommand {
/**
* Help text to show players. A usage message will be also shown below it.
*/
String[] helpText() default {};
}
@RequiredArgsConstructor
protected static class SubcommandData<T extends Command2> {
public final Method method;
public final T command;
public final String[] helpText;
}
public Command2() {
path = getcmdpath();
}
/**
* Adds a param converter that obtains a specific object from a string parameter.
* The converter may return null.
*
* @param cl The class of the result object
* @param converter The converter to use
* @param <T> The type of the result
*/
protected static <T> void addParamConverter(Class<T> cl, Function<String, T> converter, HashMap<Class<?>, Function<String, ?>> map) {
map.put(cl, converter);
}
protected static <T extends Command2> boolean handleCommand(CommandSender sender, String commandline,
HashMap<String, SubcommandData<T>> subcommands, HashMap<Class<?>, Function<String, ?>> paramConverters) throws Exception {
for (int i = commandline.length(); i != -1; i = commandline.lastIndexOf(' ', i - 1)) {
String subcommand = commandline.substring(0, i).toLowerCase();
SubcommandData sd = subcommands.get(subcommand); //O(1)
if (sd == null) continue; //TODO: This will run each time someone runs any command
val params = new ArrayList<Object>(sd.method.getParameterCount());
int j = subcommand.length(), pj;
Class<?>[] parameterTypes = sd.method.getParameterTypes();
if (parameterTypes.length == 0)
throw new Exception("No sender parameter for method '" + sd.method + "'");
val sendertype = parameterTypes[0];
final ChromaGamerBase cg;
if (sendertype.isAssignableFrom(sender.getClass()))
params.add(sender); //The command either expects a CommandSender or it is a Player, or some other expected type
else if (ChromaGamerBase.class.isAssignableFrom(sendertype)
&& (cg = ChromaGamerBase.getFromSender(sender)) != null
&& cg.getClass() == sendertype) //The command expects a user of our system
params.add(cg);
else {
sender.sendMessage("§cYou need to be a " + sendertype.getSimpleName() + " to use this command.");
return true;
}
for (int i1 = 1; i1 < parameterTypes.length; i1++) {
Class<?> cl = parameterTypes[i1];
pj = j + 1; //Start index
if (pj == commandline.length() + 1) { //No param given
params.add(null);
continue; //Fill the remaining params with nulls
}
j = commandline.indexOf(' ', j + 1); //End index
if (j == -1) //Last parameter
j = commandline.length();
String param = commandline.substring(pj, j);
if (cl == String.class) {
params.add(param);
continue;
}
val conv = paramConverters.get(cl);
if (conv == null)
throw new Exception("No suitable converter found for parameter type '" + cl.getCanonicalName() + "' for command '" + sd.method.toString() + "'");
params.add(conv.apply(param));
}
//System.out.println("Our params: "+params);
val ret = sd.method.invoke(sd.command, params.toArray()); //I FORGOT TO TURN IT INTO AN ARRAY (for a long time)
if (ret instanceof Boolean) {
if (!(boolean) ret) //Show usage
sender.sendMessage(sd.helpText);
} else if (ret != null)
throw new Exception("Wrong return type! Must return a boolean or void. Return value: "+ret);
return true; //We found a method
}
return false; //Didn't handle
} //TODO: Add to the help
protected static <T extends Command2> void registerCommand(T command, HashMap<String, SubcommandData<T>> subcommands, char commandChar) {
val path = command.getCommandPath();
try { //Register the default handler first so it can be reliably overwritten
val method = command.getClass().getMethod("def", CommandSender.class, String.class);
val cc = command.getClass().getAnnotation(CommandClass.class);
var ht = cc == null ? new String[0] : cc.helpText();
String[] both = Arrays.copyOf(ht, ht.length + 1);
both[ht.length] = "Usage: " + commandChar + path; //TODO: Print subcommands
ht = both;
subcommands.put(commandChar + path, new SubcommandData<>(method, command, ht)); //TODO: Disable components when the plugin is disabled
} catch (Exception e) {
TBMCCoreAPI.SendException("Could not register default handler for command /" + path, e);
} //Continue on
for (val method : command.getClass().getMethods()) {
val ann = method.getAnnotation(Subcommand.class);
if (ann != null) {
val cc = command.getClass().getAnnotation(CommandClass.class);
var ht = ann.helpText().length != 0 || cc == null ? ann.helpText() : cc.helpText(); //If cc is null then it's empty array
val subcommand = commandChar + path + //Add command path (class name by default)
(method.getName().equals("def") ? "" : " " + method.getName().replace('_', ' ').toLowerCase()); //Add method name, unless it's 'def'
ht = getHelpText(method, ht, subcommand);
subcommands.put(subcommand, new SubcommandData<>(method, command, ht)); //Result of the above (def) is that it will show the help text
}
}
}
private static String[] getHelpText(Method method, String[] ht, String subcommand) { //TODO: helpText[0]="§6---- "+helpText[0]+" ----";
val str = method.getDeclaringClass().getResourceAsStream("/commands.yml");
if (str == null)
TBMCCoreAPI.SendException("Error while getting command data!", new Exception("Resource not found!"));
else {
YamlConfiguration yc = YamlConfiguration.loadConfiguration(new InputStreamReader(str)); //Generated by ButtonProcessor
val ccs = yc.getConfigurationSection(method.getDeclaringClass().getCanonicalName());
if (ccs != null) {
val cs = ccs.getConfigurationSection(method.getName());
if (cs != null) {
val mname = cs.getString("method");
val params = cs.getString("params");
val goodname = method.getName() + "(" + Arrays.stream(method.getParameterTypes()).map(cl -> cl.getCanonicalName()).collect(Collectors.joining(",")) + ")";
if (goodname.equals(mname) && params != null) {
String[] both = Arrays.copyOf(ht, ht.length + 1);
both[ht.length] = "Usage: " + subcommand + " " + params;
ht = both;
} else
TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("Method '" + method.toString() + "' != " + mname + " or params is " + params));
} else
TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("cs is " + cs));
} else
TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("ccs is " + ccs + " - class: " + method.getDeclaringClass().getCanonicalName()));
}
return ht;
}
private final String path;
/**
* The command's path, or name if top-level command.<br>
* For example:<br>
* "u admin updateplugin" or "u" for the top level one<br>
* <u>The path must be lowercase!</u><br>
*
* @return The command path, <i>which is the command class name by default</i> (removing any "command" from it) - Change via the {@link CommandClass} annotation
*/
public final String getCommandPath() {
return path;
}
private String getcmdpath() {
if (!getClass().isAnnotationPresent(CommandClass.class))
throw new RuntimeException(
"No @CommandClass annotation on command class " + getClass().getSimpleName() + "!");
Function<Class<?>, String> getFromClass = cl -> cl.getSimpleName().toLowerCase().replace("commandbase", "") // <-- ...
.replace("command", "");
String path = getClass().getAnnotation(CommandClass.class).path();
path = path.length() == 0 ? getFromClass.apply(getClass()) : path;
return path;
}
} //TODO: Test support of Player instead of CommandSender

View file

@ -0,0 +1,24 @@
package buttondevteam.lib.chat;
import org.bukkit.command.CommandSender;
import java.util.HashMap;
import java.util.function.Function;
public class Command2MC extends Command2 {
private static HashMap<String, SubcommandData<Command2MC>> subcommands = new HashMap<>();
private static HashMap<Class<?>, Function<String, ?>> paramConverters = new HashMap<>();
public static boolean handleCommand(CommandSender sender, String commandLine) throws Exception {
return handleCommand(sender, commandLine, subcommands, paramConverters);
}
public static void registerCommand(Command2MC command) {
registerCommand(command, subcommands, '/');
}
public static <T> void addParamConverter(Class<T> cl, Function<String, T> converter) {
addParamConverter(cl, converter, paramConverters);
}
}

View file

@ -38,7 +38,7 @@ public @interface CommandClass {
boolean excludeFromPath() default false; boolean excludeFromPath() default false;
/** /**
* The help text to show for the players. * The help text to show for the players. A usage message will be also shown below it.
* *
* @return The help text * @return The help text
*/ */

View file

@ -1,9 +1,9 @@
package buttondevteam.lib.chat; package buttondevteam.lib.chat;
import buttondevteam.component.channel.Channel;
import buttondevteam.component.channel.Channel.RecipientTestResult;
import buttondevteam.core.CommandCaller; import buttondevteam.core.CommandCaller;
import buttondevteam.core.MainPlugin; import buttondevteam.core.MainPlugin;
import buttondevteam.core.component.channel.Channel;
import buttondevteam.core.component.channel.Channel.RecipientTestResult;
import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatEvent;
import buttondevteam.lib.TBMCChatPreprocessEvent; import buttondevteam.lib.TBMCChatPreprocessEvent;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
@ -160,7 +160,7 @@ public class TBMCChatAPI {
} catch (Exception e) { } catch (Exception e) {
TBMCCoreAPI.SendException("An error occured while registering command " + thecmdclass.getSimpleName(), e); TBMCCoreAPI.SendException("An error occured while registering command " + thecmdclass.getSimpleName(), e);
} }
} //TODO: onCommand(CommandSender sender, String alias, int arg1, String arg2) (planned for a while) }
/** /**
* <p> * <p>

View file

@ -1,6 +1,6 @@
package buttondevteam.lib.player; package buttondevteam.lib.player;
import buttondevteam.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
public class ChannelPlayerData { //I just want this to work public class ChannelPlayerData { //I just want this to work

View file

@ -1,6 +1,6 @@
package buttondevteam.lib.player; package buttondevteam.lib.player;
import buttondevteam.component.channel.Channel; import buttondevteam.core.component.channel.Channel;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import com.google.common.collect.HashBiMap; import com.google.common.collect.HashBiMap;
import lombok.val; import lombok.val;

View file

@ -1,6 +1,6 @@
package buttondevteam.lib.player; package buttondevteam.lib.player;
import buttondevteam.component.towny.TownyComponent; import buttondevteam.core.component.towny.TownyComponent;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;

View file

@ -1,4 +1,4 @@
name: ButtonCore name: ThorpeCore
main: buttondevteam.core.MainPlugin main: buttondevteam.core.MainPlugin
version: 1.0 version: 1.0
author: TBMCPlugins author: TBMCPlugins
@ -15,3 +15,4 @@ commands:
description: Add or remove a member description: Add or remove a member
component: component:
description: Enable or disable or list components description: Enable or disable or list components
dontrunthiscmd:

View file

@ -12,6 +12,13 @@
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.21" level="project" />
<orderEntry type="library" name="Maven: org.spigotmc:spigot-api:1.12.2-R0.1-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" />
<orderEntry type="library" name="Maven: com.googlecode.json-simple:json-simple:1.1.1" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:21.0" level="project" />
<orderEntry type="library" name="Maven: com.google.code.gson:gson:2.8.0" level="project" />
<orderEntry type="library" name="Maven: net.md-5:bungeecord-chat:1.12-SNAPSHOT" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:3.8.1" level="project" /> <orderEntry type="library" scope="TEST" name="Maven: junit:junit:3.8.1" level="project" />
</component> </component>
</module> </module>

View file

@ -1,40 +1,60 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <repositories>
<groupId>com.github.TBMCPlugins</groupId> <repository>
<artifactId>ButtonCore</artifactId> <id>spigot-repo</id>
<version>master-SNAPSHOT</version> <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</parent> </repository>
<groupId>com.github.TBMCPlugins.ButtonCore</groupId> </repositories>
<artifactId>ButtonProcessor</artifactId> <dependencies>
<packaging>jar</packaging> <dependency>
<groupId>org.yaml</groupId>
<name>ButtonProcessor</name> <artifactId>snakeyaml</artifactId>
<url>http://maven.apache.org</url> <version>1.21</version>
<scope>compile</scope>
<build> </dependency>
<plugins> <dependency>
<plugin> <groupId>org.spigotmc</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>spigot-api</artifactId>
<configuration> <version>1.12.2-R0.1-SNAPSHOT</version>
<source>1.8</source> <scope>compile</scope>
<target>1.8</target> </dependency>
<compilerArgument>-proc:none</compilerArgument> </dependencies>
</configuration> <parent>
</plugin> <groupId>com.github.TBMCPlugins</groupId>
<plugin> <artifactId>ButtonCore</artifactId>
<groupId>org.apache.maven.plugins</groupId> <version>master-SNAPSHOT</version>
<artifactId>maven-surefire-plugin</artifactId> </parent>
<configuration> <groupId>com.github.TBMCPlugins.ButtonCore</groupId>
<useSystemClassLoader>false <artifactId>ButtonProcessor</artifactId>
</useSystemClassLoader> <!-- https://stackoverflow.com/a/53012553/2703239 --> <packaging>jar</packaging>
</configuration>
</plugin> <name>ButtonProcessor</name>
</plugins> <url>http://maven.apache.org</url>
</build>
<build>
<properties> <plugins>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <plugin>
</properties> <artifactId>maven-compiler-plugin</artifactId>
</project> <configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgument>-proc:none</compilerArgument>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useSystemClassLoader>false
</useSystemClassLoader> <!-- https://stackoverflow.com/a/53012553/2703239 -->
</configuration>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View file

@ -1,17 +1,25 @@
package buttondevteam.buttonproc; package buttondevteam.buttonproc;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion; import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.*;
import javax.lang.model.element.Element; import javax.tools.Diagnostic;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind; import javax.tools.Diagnostic.Kind;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
@SupportedAnnotationTypes("buttondevteam.*") @SupportedAnnotationTypes("buttondevteam.*")
public class ButtonProcessor extends AbstractProcessor { public class ButtonProcessor extends AbstractProcessor {
@ -23,7 +31,7 @@ public class ButtonProcessor extends AbstractProcessor {
System.out.println("Processing " + targetcl); System.out.println("Processing " + targetcl);
List<? extends AnnotationMirror> annotationMirrors = processingEnv.getElementUtils() List<? extends AnnotationMirror> annotationMirrors = processingEnv.getElementUtils()
.getAllAnnotationMirrors(targetcl); .getAllAnnotationMirrors(targetcl);
System.out.println("Annotations: " + annotationMirrors); //System.out.println("Annotations: " + annotationMirrors);
Function<String, Boolean> hasAnnotation = ann -> annotationMirrors.stream() Function<String, Boolean> hasAnnotation = ann -> annotationMirrors.stream()
.anyMatch(am -> am.getAnnotationType().toString().contains(ann)); .anyMatch(am -> am.getAnnotationType().toString().contains(ann));
if (hasAnnotation.apply("ChromaGamerEnforcer") && !hasAnnotation.apply("UserClass") if (hasAnnotation.apply("ChromaGamerEnforcer") && !hasAnnotation.apply("UserClass")
@ -36,15 +44,67 @@ public class ButtonProcessor extends AbstractProcessor {
"No PlayerClass annotation found for " + targetcl.getSimpleName(), targetcl); "No PlayerClass annotation found for " + targetcl.getSimpleName(), targetcl);
for (AnnotationMirror annotation : annotationMirrors) { for (AnnotationMirror annotation : annotationMirrors) {
String type = annotation.getAnnotationType().toString(); String type = annotation.getAnnotationType().toString();
System.out.println("Type: " + type); //System.out.println("Type: " + type);
} }
processSubcommands(targetcl, annotationMirrors);
} }
} }
try {
if (found) {
FileObject fo = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", "commands.yml");
yc.save(new File(fo.toUri()));
found = false;
}
} catch (IOException e) {
e.printStackTrace();
}
return true; // claim the annotations return true; // claim the annotations
} }
@Override private YamlConfiguration yc = new YamlConfiguration();
private boolean found = false;
private void processSubcommands(Element targetcl, List<? extends AnnotationMirror> annotationMirrors) {
if (!(targetcl instanceof ExecutableElement))
return;
//System.out.println("Annotations: "+annotationMirrors);
if (annotationMirrors.stream().noneMatch(an -> an.getAnnotationType().toString().endsWith("Subcommand")))
return;
//System.out.print("Processing method: " + targetcl.getEnclosingElement()+" "+targetcl);
ConfigurationSection cs = yc.createSection(targetcl.getEnclosingElement().toString()
+ "." + targetcl.getSimpleName().toString()); //Need to do the 2 config sections at once so it doesn't overwrite the class section
System.out.println(targetcl);
cs.set("method", targetcl.toString());
cs.set("params", ((ExecutableElement) targetcl).getParameters().stream().skip(1).map(p -> {
//String tn=p.asType().toString();
//return tn.substring(tn.lastIndexOf('.')+1)+" "+p.getSimpleName();
boolean optional = p.getAnnotationMirrors().stream().anyMatch(am -> am.getAnnotationType().toString().endsWith("Optional"));
if (optional)
return "[" + p.getSimpleName() + "]";
return "<" + p.getSimpleName() + ">";
}).collect(Collectors.joining(" ")));
//System.out.println();
found = true;
}
@Override
public SourceVersion getSupportedSourceVersion() { public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported(); return SourceVersion.latestSupported();
} }
private String fetchSourcePath() {
try {
JavaFileObject generationForPath = processingEnv.getFiler().createSourceFile("PathFor" + getClass().getSimpleName());
Writer writer = generationForPath.openWriter();
String sourcePath = generationForPath.toUri().getPath();
writer.close();
generationForPath.delete();
return sourcePath;
} catch (IOException e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Unable to determine source file path!");
}
return "";
}
} }