Skip to content

Commit

Permalink
1.1.6: Dependency download improvements
Browse files Browse the repository at this point in the history
- Small improvements for 'AnnoyingMessage'
- Merged 'AnnoyingCooldown#check()' into 'AnnoyingCooldown#isOnCooldown()'
- 'AnnoyingUtility#getString(AnnoyingPlugin, String)' now checks if 'AnnoyingPlugin#messages' is 'null'
- Added 'ApiCommand' to give the API plugin a command to get the API's version
  - Added 'version' message to 'messages.yml'
  - Added 'commands' and 'permissions' sections to 'plugin.yml'
- Added 'AnnoyingCommandRegister'
  - This has methods to register commands from another plugin
  - Used when downloading/enabling dependencies
- Added test JAR
  - The test JAR is a plugin that uses the API
  - This will allow me to more easily test stuff before release
  - The plugin contains a simple command, listener, dependency, and a few other tests
- Improved 'AnnoyingDependency'
  - Added '#enableAfterDownload' option, if 'true', AnnoyingAPI will attempt to load/enable the plugin once it's downloaded
  - Added '#getFile()' to get the 'File' of the new JAR file of the dependency
  - Changed '#isInstalled()' to '#isNotInstalled()' because it was always inverted
- Improved 'AnnoyingDownload'
  - '#dependencies' is now a 'List', so they will be installed in the order of when they were added (roughly, threads mess it up a bit)
  - Removed '#finishTask', 'FinishTask', and 'AnnoyingOptions#dependencyFinishTask'
  - If the Spigot plugin is external and the external URL ends with '.jar', it will treat it as a 'Platform.EXTERNAL'
  - '#finish' (now '#finish(AnnoyingDependency, boolean)') has been improved to allow dependencies to be loaded, enabled, and their commands registered
  - Added '#registerCommands(Plugin)' to register a plugin's (dependency) commands
- Improved 'AnnoyingPlugin'
  - Added static '#missingDependencies' to track the missing dependencies from ALL plugins using the API
  - Added static '#commandRegister' to initialize a new 'AnnoyingCommandRegister'
  - Moved API option setting from the constructor to '#onEnable()'
  - Adjusted algorithm for getting missing dependencies
  - Only run 'AnnoyingDownload#downloadPlugins' from the API instance
  • Loading branch information
srnyx committed Dec 8, 2022
1 parent 7bde095 commit 90add51
Show file tree
Hide file tree
Showing 18 changed files with 610 additions and 93 deletions.
41 changes: 31 additions & 10 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
description = "AnnoyingAPI"
version = "1.1.5"
version = "1.1.6"
group = "xyz.srnyx"

plugins {
java
`maven-publish`
}

repositories {
mavenCentral() // org.spigotmc:spigot-api
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // org.spigotmc:spigot-api
maven("https://oss.sonatype.org/content/repositories/snapshots/") // org.spigotmc:spigot-api
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") // org.spigotmc:spigot
maven("https://oss.sonatype.org/content/repositories/snapshots/") // org.spigotmc:spigot
mavenCentral() // net.md-5:bungeecord-api
}

dependencies {
Expand All @@ -20,12 +15,26 @@ dependencies {
compileOnly(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar"))))
}

plugins {
java
`maven-publish`
}

// Allow compileOnly dependencies to be used in tests
configurations {
testCompileOnly {
extendsFrom(configurations.compileOnly.get())
}
}

// Set Java version and Javadoc
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
withJavadocJar()
}

// Maven publishing for Jitpack
configure<PublishingExtension> {
publications {
create<MavenPublication>("maven") {
Expand All @@ -36,14 +45,26 @@ configure<PublishingExtension> {
}

tasks {
// Text encoding
compileJava {
options.encoding = "UTF-8"
}

processResources {
// Replace version in plugin.yml
@Suppress("UnstableApiUsage")
withType<ProcessResources> {
inputs.property("version", project.version)
filesMatching("**/plugin.yml") {
expand("version" to project.version)
}
}

// Create test JAR
assemble {
dependsOn("testJar")
}
register<Jar>("testJar") {
archiveClassifier.set("test")
from(sourceSets["test"].output)
}
}
137 changes: 137 additions & 0 deletions src/main/java/xyz/srnyx/annoyingapi/AnnoyingCommandRegister.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package xyz.srnyx.annoyingapi;

import org.bukkit.Bukkit;
import org.bukkit.command.Command;

import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


/**
* A class that registers commands using the Brigadier API
* <p><b>All</b> credit for this class goes to <a href="https://spigotmc.org/resources/authors/623700">realEntity303</a>, author of <a href="https://spigotmc.org/resources/88135">PlugManX</a>
*/
public class AnnoyingCommandRegister {
private String nmsVersion;
private Class<?> minecraftServerClass;
private Method getServerMethod;
private Field vanillaCommandDispatcherField;
private Constructor<?> bukkitcommandWrapperConstructor;
private Method registerMethod;
private Method syncCommandsMethod;
private Method aMethod;

/**
* Initialize the command register
*/
public AnnoyingCommandRegister() {
// nmsVersion
try {
this.nmsVersion = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
} catch (final ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}

// minecraftServerClass
try {
this.minecraftServerClass = Class.forName("net.minecraft.server." + this.nmsVersion + ".MinecraftServer");
} catch (final ClassNotFoundException e) {
try {
this.minecraftServerClass = Class.forName("net.minecraft.server.MinecraftServer");
} catch (final ClassNotFoundException e2) {
e2.addSuppressed(e);
e2.printStackTrace();
}
}

// getServerMethod
try {
this.getServerMethod = this.minecraftServerClass.getMethod("getServer");
this.getServerMethod.setAccessible(true);
} catch (final NoSuchMethodException e) {
e.printStackTrace();
}

// vanillaCommandDispatcherField
try {
this.vanillaCommandDispatcherField = this.minecraftServerClass.getDeclaredField("vanillaCommandDispatcher");
this.vanillaCommandDispatcherField.setAccessible(true);
} catch (final NoSuchFieldException e) {
e.printStackTrace();
}

// bukkitcommandWrapperConstructor
try {
this.bukkitcommandWrapperConstructor = Class.forName("org.bukkit.craftbukkit." + this.nmsVersion + ".command.BukkitCommandWrapper").getDeclaredConstructor(Class.forName("org.bukkit.craftbukkit." + this.nmsVersion + ".CraftServer"), Command.class);
this.bukkitcommandWrapperConstructor.setAccessible(true);
} catch (final NoSuchMethodException | ClassNotFoundException e) {
e.printStackTrace();
}

// registerMethod
try {
this.registerMethod = Class.forName("org.bukkit.craftbukkit." + this.nmsVersion + ".command.BukkitCommandWrapper").getMethod("register", com.mojang.brigadier.CommandDispatcher.class, String.class);
this.registerMethod.setAccessible(true);
} catch (final NoSuchMethodException | ClassNotFoundException e) {
e.printStackTrace();
}

// syncCommandsMethod
try {
this.syncCommandsMethod = Class.forName("org.bukkit.craftbukkit." + this.nmsVersion + ".CraftServer").getDeclaredMethod("syncCommands");
this.syncCommandsMethod.setAccessible(true);
} catch (final NoSuchMethodException | ClassNotFoundException e) {
e.printStackTrace();
}
}

/**
* Register a command from another plugin
*
* @param command the command to register
* @param fallbackPrefix the fallback command prefix
*/
public void register(@NotNull Command command, @NotNull String fallbackPrefix) {
if (nmsVersion == null) return;

// Get commandDispatcher
final Object commandDispatcher;
try {
commandDispatcher = this.vanillaCommandDispatcherField.get(this.getServerMethod.invoke(this.minecraftServerClass));
} catch (final IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return;
}

// Get aMethod
if (this.aMethod == null) try {
this.aMethod = commandDispatcher.getClass().getDeclaredMethod("a");
this.aMethod.setAccessible(true);
} catch (final NoSuchMethodException e) {
e.printStackTrace();
return;
}

// Register command
try {
this.registerMethod.invoke(this.bukkitcommandWrapperConstructor.newInstance(Bukkit.getServer(), command), this.aMethod.invoke(commandDispatcher), fallbackPrefix);
} catch (final IllegalAccessException | InvocationTargetException | InstantiationException e) {
e.printStackTrace();
}
}

/**
* Refreshes the command list
*/
public void sync() {
try {
this.syncCommandsMethod.invoke(Bukkit.getServer());
} catch (final IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
13 changes: 4 additions & 9 deletions src/main/java/xyz/srnyx/annoyingapi/AnnoyingCooldown.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,19 +86,14 @@ public long getDuration() {
}

/**
* A {@code boolean} of whether the cooldown is active
* A {@code boolean} of whether the cooldown is active. If the cooldown is not active, it will be removed from {@link AnnoyingPlugin#cooldowns}
*
* @return whether the player is on cooldown
*/
public boolean isOnCooldown() {
return getRemaining() > 0;
}

/**
* If the player should no longer be on cooldown, this will remove them from {@link AnnoyingPlugin#cooldowns}
*/
public void check() {
if (!isOnCooldown()) stop();
final boolean onCooldown = getRemaining() > 0;
if (!onCooldown) stop();
return onCooldown;
}

/**
Expand Down
26 changes: 19 additions & 7 deletions src/main/java/xyz/srnyx/annoyingapi/AnnoyingDependency.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,37 @@
public class AnnoyingDependency {
@NotNull public final String name;
@NotNull public final Map<AnnoyingDownload.Platform, String> platforms;
public final boolean enableAfterDownload;

/**
* Creates a new dependency instance
*
* @param name the name of the dependency (from it's {@code plugin.yml})
* @param platforms the platforms the dependency can be downloaded from
* @param name the name of the dependency (from it's {@code plugin.yml})
* @param platforms the platforms the dependency can be downloaded from
* @param enableAfterDownload whether or not to attempt to enable the dependency after it has been downloaded
*/
@Contract(pure = true)
public AnnoyingDependency(@NotNull String name, @NotNull Map<AnnoyingDownload.Platform, String> platforms) {
public AnnoyingDependency(@NotNull String name, @NotNull Map<AnnoyingDownload.Platform, String> platforms, boolean enableAfterDownload) {
this.name = name;
this.platforms = platforms;
this.enableAfterDownload = enableAfterDownload;
}

/**
* This uses {@link Bukkit#getPluginManager()} to check if the dependency is installed. So it's vital that {@link #name} is from the plugin's {@code plugin.yml}
* Gets the new file of the dependency
*
* @return whether the dependency is currently installed
* @return the new file of the dependency ({@link #name}{@code .jar})
*/
public boolean isInstalled() {
return Bukkit.getPluginManager().getPlugin(name) != null || new File(Bukkit.getUpdateFolderFile().getParentFile(), name + ".jar").exists();
public File getFile() {
return new File(Bukkit.getUpdateFolderFile().getParentFile(), name + ".jar");
}

/**
* This uses {@link Bukkit#getPluginManager()} to check if the dependency isn't installed. So it's vital that {@link #name} is from the plugin's {@code plugin.yml}
*
* @return whether the dependency isn't currently installed
*/
public boolean isNotInstalled() {
return Bukkit.getPluginManager().getPlugin(name) == null;
}
}
Loading

0 comments on commit 90add51

Please sign in to comment.