This commit is contained in:
Paul Reilly 2023-05-15 01:30:37 -05:00
parent 5a395554cf
commit 6f400e505c
57 changed files with 699 additions and 10 deletions

21
Corvo/build.gradle Normal file
View File

@ -0,0 +1,21 @@
plugins {
id 'java'
}
group = 'me.totalfreedom'
version = '1.0.0'
repositories {
mavenCentral()
}
dependencies {
compileOnly project(":Patchwork")
testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter'
}
test {
useJUnitPlatform()
}

View File

@ -0,0 +1,23 @@
package me.totalfreedom.corvo;
import me.totalfreedom.base.CommonsBase;
import org.bukkit.plugin.java.JavaPlugin;
public class Corvo extends JavaPlugin
{
@Override
public void onEnable() {
CommonsBase.getInstance()
.getRegistrations()
.getModuleRegistry()
.addModule(this);
}
@Override
public void onDisable() {
CommonsBase.getInstance()
.getRegistrations()
.getModuleRegistry()
.removeModule(this);
}
}

View File

@ -10,12 +10,16 @@ repositories {
} }
dependencies { dependencies {
compileOnly project(":Commons") compileOnly project(":Patchwork")
compileOnly "com.discord4j:discord4j-core:3.2.3"
compileOnly "com.discord4j:discord4j-commons:3.2.3"
testImplementation platform('org.junit:junit-bom:5.9.1') testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter'
} }
var weight = 2
test { test {
useJUnitPlatform() useJUnitPlatform()
} }

View File

@ -0,0 +1,8 @@
name: Datura
main: me.totalfreedom.datura.Datura
version: 1.0.0
author: TotalFreedom
description: Data Manager for the Freedom Network Suite
libraries:
- com.discord4j:discord4j-core:3.2.3
- com.discord4j:discord4j-commons:3.2.3

42
Fossil/.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

21
Fossil/build.gradle Normal file
View File

@ -0,0 +1,21 @@
plugins {
id 'java'
}
group = 'me.totalfreedom'
version = '1.0.0'
repositories {
mavenCentral()
}
dependencies {
compileOnly project(":Patchwork")
testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter'
}
test {
useJUnitPlatform()
}

View File

@ -0,0 +1,16 @@
package me.totalfreedom.fossil;
import me.totalfreedom.base.CommonsBase;
import org.bukkit.plugin.java.JavaPlugin;
public class Fossil extends JavaPlugin
{
@Override
public void onEnable()
{
CommonsBase.getInstance()
.getRegistrations()
.getModuleRegistry()
.addModule(this);
}
}

View File

@ -0,0 +1,36 @@
package me.totalfreedom.fossil.command;
import me.totalfreedom.command.*;
import me.totalfreedom.command.annotation.Base;
import me.totalfreedom.command.annotation.Info;
import me.totalfreedom.command.annotation.Permissive;
import me.totalfreedom.command.annotation.Subcommand;
import me.totalfreedom.fossil.Fossil;
import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Info(name = "kick", description = "Kick a player", usage = "/<command> <player>")
@Permissive(perm = "fossil.kick")
public class KickCommand extends CommandBase
{
public KickCommand(Fossil plugin) {
super(plugin);
}
@Base
public void run(CommandSender sender) {
sender.sendMessage(Component.text("You must specify a player to kick."));
}
@Subcommand(permission = "fossil.kick", args = {Player.class, String.class})
public void kickPlayer(Player player, String string) {
player.kick(Component.text(string));
}
// TODO: Write the code to make this work properly.
@Subcommand(name = "info", permission = "fossil.kick.info", args = {Player.class})
public void playerinfo(Player player) {
}
}

42
Patchwork/.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

View File

@ -9,13 +9,12 @@ dependencies {
api 'io.projectreactor:reactor-core:3.5.4' api 'io.projectreactor:reactor-core:3.5.4'
api 'org.reflections:reflections:0.10.2' api 'org.reflections:reflections:0.10.2'
api 'org.slf4j:slf4j-api:1.7.36' api 'org.slf4j:slf4j-api:1.7.36'
api 'co.aikar:acf-paper:0.5.1-SNAPSHOT'
testImplementation platform('org.junit:junit-bom:5.9.1') testImplementation platform('org.junit:junit-bom:5.9.1')
testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter'
} }
ext.weight = 1 var weight = 1
test { test {
useJUnitPlatform() useJUnitPlatform()

View File

@ -16,6 +16,63 @@ public interface Context<T>
{ {
T get(); T get();
default @Nullable String asString()
{
if (get() instanceof String string)
{
return string;
} else
{
return null;
}
}
default @Nullable Boolean asBoolean()
{
if (get() instanceof Boolean bool)
{
return bool;
} else
{
return null;
}
}
default @Nullable Double asDouble()
{
if (get() instanceof Double doub)
{
return doub;
} else
{
return null;
}
}
default @Nullable Integer asInt() {
if (get() instanceof Integer integer) {
return integer;
} else {
return null;
}
}
default @Nullable Long asLong() {
if (get() instanceof Long longg) {
return longg;
} else {
return null;
}
}
default @Nullable Float asFloat() {
if (get() instanceof Float floatt) {
return floatt;
} else {
return null;
}
}
default @Nullable Player asPlayer() default @Nullable Player asPlayer()
{ {
if (get() instanceof Player player) if (get() instanceof Player player)
@ -38,7 +95,7 @@ public interface Context<T>
} }
} }
default @NotNull String asLiteral() default @NotNull String literal()
{ {
return get().toString(); return get().toString();
} }

View File

@ -0,0 +1,120 @@
package me.totalfreedom.command;
import jdk.jshell.MethodSnippet;
import me.totalfreedom.api.Context;
import me.totalfreedom.command.annotation.Subcommand;
import me.totalfreedom.provider.ContextProvider;
import me.totalfreedom.utils.FreedomLogger;
import net.kyori.adventure.text.Component;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.PluginIdentifiableCommand;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class BukkitDelegator extends Command implements PluginIdentifiableCommand
{
private final JavaPlugin plugin;
private final CommandBase command;
private final boolean noConsole;
BukkitDelegator(final JavaPlugin plugin, final CommandBase command)
{
super(command.getInfo().name());
this.plugin = plugin;
this.command = command;
this.setDescription(command.getInfo().description());
this.setUsage(command.getInfo().usage());
this.setPermission(command.getPerms().perm());
this.setAliases(Arrays.asList(command.getInfo().aliases()));
this.permissionMessage(Component.text(command.getPerms().noPerms()));
this.noConsole = command.getPerms().onlyPlayers();
}
@Override
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args)
{
if (commandLabel.isEmpty() || !commandLabel.equalsIgnoreCase(getName()))
return false;
if (sender instanceof ConsoleCommandSender && noConsole)
{
sender.sendMessage(Component.text("This command can only be run by players."));
return true;
}
if (getPermission() != null && !sender.hasPermission(getPermission()))
{
Component permissionMessage = permissionMessage();
if (permissionMessage == null)
permissionMessage = Component.text("You do not have permission to use this command.");
sender.sendMessage(permissionMessage);
return true;
}
if (args.length > 0)
{
ContextProvider provider = new ContextProvider();
Set<Subcommand> nodes = command.getSubcommands().keySet();
for (Subcommand node : nodes) {
Class<?>[] argTypes = node.args();
if (argTypes.length != args.length)
continue;
Object[] objects = new Object[0];
for (int i = 0; i < argTypes.length; i++) {
Class<?> argType = argTypes[i];
String arg = args[i];
if (argType == String.class)
continue;
Context<?> context = () -> provider.fromString(arg);
if (!argType.isInstance(context.get())) {
throw new IllegalStateException();
}
objects = Arrays.copyOf(objects, objects.length + 1);
objects[objects.length - 1] = context.get();
}
try
{
command.getSubcommands().get(node).invoke(command, objects);
} catch (Exception ex)
{
FreedomLogger.getLogger("Patchwork")
.error(ex);
}
}
return false;
}
if (command.getBaseMethodPair() != null) {
try
{
command.getBaseMethodPair().getValue().invoke(command, sender);
} catch (Exception ex)
{
FreedomLogger.getLogger("Patchwork")
.error(ex);
}
}
return true;
}
@Override
public @NotNull Plugin getPlugin()
{
return this.plugin;
}
}

View File

@ -0,0 +1,72 @@
package me.totalfreedom.command;
import me.totalfreedom.command.annotation.Base;
import me.totalfreedom.command.annotation.Info;
import me.totalfreedom.command.annotation.Permissive;
import me.totalfreedom.command.annotation.Subcommand;
import me.totalfreedom.utils.Pair;
import org.bukkit.plugin.java.JavaPlugin;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
public abstract class CommandBase
{
private final JavaPlugin plugin;
private final Info info;
private final Permissive perms;
private final Map<Subcommand, Method> subcommands;
private final Pair<Base, Method> baseMethodPair;
protected CommandBase(final JavaPlugin plugin)
{
this.info = this.getClass().getDeclaredAnnotation(Info.class);
this.perms = this.getClass().getDeclaredAnnotation(Permissive.class);
this.plugin = plugin;
this.subcommands = new HashMap<>();
if (this.getClass().isAnnotationPresent(Base.class))
{
Method method = Stream.of(this.getClass().getDeclaredMethods())
.filter(m -> m.isAnnotationPresent(Base.class))
.findFirst()
.orElseThrow(() -> new RuntimeException("Base annotation present but no method found."));
this.baseMethodPair = new Pair<>(method.getDeclaredAnnotation(Base.class), method);
} else
{
this.baseMethodPair = null;
}
Stream.of(this.getClass().getDeclaredMethods())
.filter(method -> method.isAnnotationPresent(Subcommand.class))
.forEach(method -> this.subcommands.put(method.getDeclaredAnnotation(Subcommand.class), method));
}
public Pair<Base, Method> getBaseMethodPair()
{
return baseMethodPair;
}
Info getInfo()
{
return this.info;
}
Permissive getPerms()
{
return this.perms;
}
public JavaPlugin getPlugin()
{
return this.plugin;
}
Map<Subcommand, Method> getSubcommands()
{
return this.subcommands;
}
}

View File

@ -0,0 +1,25 @@
package me.totalfreedom.command;
import org.bukkit.Bukkit;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.java.JavaPlugin;
public class CommandHandler
{
private final JavaPlugin plugin;
public CommandHandler(JavaPlugin plugin)
{
this.plugin = plugin;
}
// TODO: Figure out how to use CommandExecutor and TabCompleter.
// We need to find a way to resolve PluginCommands so we can
// set the executor and tab completer as necessary.
// OR we need to find an alternative way to process tab completions.
public <T extends CommandBase> void registerCommand(T command) {
BukkitDelegator delegate = new BukkitDelegator(plugin, command);
Bukkit.getCommandMap().register(plugin.getName(), delegate);
}
}

View File

@ -0,0 +1,13 @@
package me.totalfreedom.command.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* This annotation is used to mark a method as the command's default method.
* This is the method that will be run to execute the command when a user inputs /{command}
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Base
{
}

View File

@ -0,0 +1,16 @@
package me.totalfreedom.command.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Info
{
String name();
String description() default "This is the default command description.";
String usage() default "/<command>";
String[] aliases() default {};
}

View File

@ -0,0 +1,14 @@
package me.totalfreedom.command.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Permissive
{
String perm();
boolean onlyPlayers() default false;
String noPerms() default "You do not have permission to use this command.";
}

View File

@ -0,0 +1,14 @@
package me.totalfreedom.command.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Subcommand
{
String name() default "";
String permission();
Class<?>[] args() default {};
}

View File

@ -24,6 +24,10 @@ public class ModuleRegistry
this.plugins.add(plugin); this.plugins.add(plugin);
} }
public void removeModule(final JavaPlugin plugin) {
this.plugins.remove(plugin);
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends JavaPlugin> ModuleProvider<T> getModule(Class<T> clazz) public <T extends JavaPlugin> ModuleProvider<T> getModule(Class<T> clazz)
{ {

View File

@ -0,0 +1,120 @@
package me.totalfreedom.provider;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.stream.Stream;
public class ContextProvider
{
public Object fromString(String string)
{
return Stream.of(toBoolean(string),
toDouble(string),
toInt(string),
toLong(string),
toFloat(string),
toPlayer(string),
toWorld(string),
toLocation(string),
toCommandSender(string),
toComponent(string))
.filter(Objects::nonNull)
.findFirst()
.orElse(string);
}
private @Nullable Boolean toBoolean(String string)
{
try
{
return Boolean.parseBoolean(string);
} catch (Exception e)
{
return null;
}
}
private @Nullable Double toDouble(String string)
{
try
{
return Double.parseDouble(string);
} catch (Exception e)
{
return null;
}
}
private @Nullable Integer toInt(String string)
{
try
{
return Integer.parseInt(string);
} catch (Exception e)
{
return null;
}
}
private @Nullable Long toLong(String string)
{
try
{
return Long.parseLong(string);
} catch (Exception e)
{
return null;
}
}
private @Nullable Float toFloat(String string)
{
try
{
return Float.parseFloat(string);
} catch (Exception e)
{
return null;
}
}
private @Nullable Player toPlayer(String string)
{
return Bukkit.getPlayer(string);
}
private @Nullable CommandSender toCommandSender(String string)
{
if (toPlayer(string) == null) return null;
return toPlayer(string);
}
private @Nullable World toWorld(String string)
{
return Bukkit.getWorld(string);
}
private @Nullable Location toLocation(String string)
{
String[] split = string.split(",");
if (split.length != 4 || toWorld(split[0]) == null) return null;
if (toDouble(split[1]) == null
|| toDouble(split[2]) == null
|| toDouble(split[3]) == null) return null;
return new Location(toWorld(split[0]), toDouble(split[1]), toDouble(split[2]), toDouble(split[3]));
}
private @Nullable Component toComponent(String string)
{
return Component.text(string);
}
}

View File

@ -0,0 +1,22 @@
package me.totalfreedom.utils;
public class Pair<K, V>
{
private final K key;
private final V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey()
{
return key;
}
public V getValue()
{
return value;
}
}

View File

@ -39,10 +39,10 @@ subprojects {
compileOnly 'com.google.code.gson:gson:2.8.8' compileOnly 'com.google.code.gson:gson:2.8.8'
compileOnly 'org.reflections:reflections:0.10.2' compileOnly 'org.reflections:reflections:0.10.2'
compileOnly 'org.slf4j:slf4j-api:1.7.36' compileOnly 'org.slf4j:slf4j-api:1.7.36'
compileOnly 'co.aikar:acf-paper:0.5.1-SNAPSHOT'
} }
sourceCompatibility = 1.17 sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
tasks.withType(JavaCompile).configureEach { tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8' options.encoding = 'UTF-8'
@ -52,9 +52,7 @@ subprojects {
useJUnitPlatform() useJUnitPlatform()
} }
ext { var weight = -1;
weight = -1
}
afterEvaluate { afterEvaluate {
if (weight == -1) { if (weight == -1) {

View File

@ -1,4 +1,6 @@
rootProject.name = 'FreedomNetworkSuite' rootProject.name = 'FreedomNetworkSuite'
include 'Commons' include 'Patchwork'
include 'Datura' include 'Datura'
include 'Fossil'
include 'Corvo'