Implement command executors, dynamicproxy

This commit is contained in:
Vankka 2022-06-25 22:33:55 +03:00
parent d4975f833a
commit 83fb75d4c0
No known key found for this signature in database
GPG Key ID: 6E50CB7A29B96AD0
31 changed files with 869 additions and 9 deletions

View File

@ -36,6 +36,9 @@ java {
withJavadocJar() withJavadocJar()
} }
// Fix template source set not being depended on/other tasks not depending on template source set
sourcesJar { dependsOn compileTemplateJava }
jar { jar {
from sourceSets.ap.output from sourceSets.ap.output
} }

View File

@ -190,7 +190,7 @@ public interface DiscordSRVApi {
ATTEMPTING_TO_CONNECT, ATTEMPTING_TO_CONNECT,
/** /**
* DiscordSRV is connected to Discord & is ready. * DiscordSRV is connected to Discord and is ready.
* @see #isReady() * @see #isReady()
*/ */
CONNECTED, CONNECTED,

View File

@ -32,7 +32,7 @@ import java.util.Optional;
/** /**
* A Minecraft json text component. Use {@link DiscordSRVApi#componentFactory()} to get an instance.<br/> * A Minecraft json text component. Use {@link DiscordSRVApi#componentFactory()} to get an instance.<br/>
* <br/> * <br/>
* This is designed to work with Adventure, see {@link #adventureAdapter(Class, Class)} & {@link #adventureAdapter(MinecraftComponentAdapter)} * This is designed to work with Adventure, see {@link #adventureAdapter(Class, Class)} and {@link #adventureAdapter(MinecraftComponentAdapter)}
* but is compatible with anything able to handle Minecraft's json format. * but is compatible with anything able to handle Minecraft's json format.
* Legacy is <b>not supported</b>. * Legacy is <b>not supported</b>.
*/ */

View File

@ -83,7 +83,7 @@ public interface DiscordUser extends JDAEntity<User>, Snowflake, Mentionable {
/** /**
* Gets the Discord user's username followed by a {@code #} and their discriminator. * Gets the Discord user's username followed by a {@code #} and their discriminator.
* @return the Discord user's username & discriminator in the following format {@code Username#1234} * @return the Discord user's username and discriminator in the following format {@code Username#1234}
*/ */
@Placeholder("user_tag") @Placeholder("user_tag")
default String getAsTag() { default String getAsTag() {

View File

@ -8,7 +8,7 @@ plugins {
version '2.0.0-SNAPSHOT' version '2.0.0-SNAPSHOT'
allprojects { subprojects {
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'java-library' apply plugin: 'java-library'
apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'com.github.johnrengelman.shadow'
@ -41,8 +41,8 @@ allprojects {
repositories { repositories {
// Snapshot repositories // Snapshot repositories
//maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } //maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
mavenLocal()
maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' } maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
//mavenLocal()
maven { maven {
url 'https://nexus.scarsz.me/content/groups/public/' url 'https://nexus.scarsz.me/content/groups/public/'
@ -63,10 +63,34 @@ allprojects {
mavenCentral() mavenCentral()
} }
// Add a 'template' source set to all projects
sourceSets {
template {
java {
compileClasspath += sourceSets.main.compileClasspath
}
}
main {
java {
srcDir sourceSets.template.output.generatedSourcesDirs.getSingleFile()
}
}
}
// Compile template source
compileJava { dependsOn compileTemplateJava }
// Fix template source set not being depended on/other tasks not depending on template source set
checkLicenseMain { dependsOn compileTemplateJava }
updateLicenseMain { dependsOn compileTemplateJava }
dependencies { dependencies {
// Test dependencies // Test dependencies
testImplementation(libs.jupiter.api) testImplementation(libs.jupiter.api)
testRuntimeOnly(libs.jupiter.engine) testRuntimeOnly(libs.jupiter.engine)
// DynamicProxy
templateAnnotationProcessor(libs.dynamicproxy)
} }
test { test {

View File

@ -35,8 +35,9 @@ allprojects {
} }
filter { filter {
includeGroup 'com.destroystokyo.paper' includeGroup 'com.destroystokyo.paper'
includeGroup 'io.papermc' includeGroup 'io.papermc.paper'
includeGroup 'org.spigotmc' includeGroup 'org.spigotmc'
includeGroup 'net.md-5'
} }
} }

View File

@ -20,6 +20,8 @@ package com.discordsrv.bukkit.console;
import com.discordsrv.bukkit.BukkitDiscordSRV; import com.discordsrv.bukkit.BukkitDiscordSRV;
import com.discordsrv.bukkit.command.game.sender.BukkitCommandSender; import com.discordsrv.bukkit.command.game.sender.BukkitCommandSender;
import com.discordsrv.bukkit.console.executor.BukkitCommandExecutorProvider;
import com.discordsrv.common.command.game.executor.CommandExecutorProvider;
import com.discordsrv.common.console.Console; import com.discordsrv.common.console.Console;
import com.discordsrv.common.logging.NamedLogger; import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.logging.backend.LoggingBackend; import com.discordsrv.common.logging.backend.LoggingBackend;
@ -29,6 +31,7 @@ import com.discordsrv.common.logging.backend.impl.Log4JLoggerImpl;
public class BukkitConsole extends BukkitCommandSender implements Console { public class BukkitConsole extends BukkitCommandSender implements Console {
private final LoggingBackend loggingBackend; private final LoggingBackend loggingBackend;
private final CommandExecutorProvider executorProvider;
public BukkitConsole(BukkitDiscordSRV discordSRV) { public BukkitConsole(BukkitDiscordSRV discordSRV) {
super(discordSRV, discordSRV.server().getConsoleSender(), () -> discordSRV.audiences().console()); super(discordSRV, discordSRV.server().getConsoleSender(), () -> discordSRV.audiences().console());
@ -45,10 +48,16 @@ public class BukkitConsole extends BukkitCommandSender implements Console {
logging = JavaLoggerImpl.getRoot(); logging = JavaLoggerImpl.getRoot();
} }
this.loggingBackend = logging; this.loggingBackend = logging;
this.executorProvider = new BukkitCommandExecutorProvider(discordSRV);
} }
@Override @Override
public LoggingBackend loggingBackend() { public LoggingBackend loggingBackend() {
return loggingBackend; return loggingBackend;
} }
@Override
public CommandExecutorProvider commandExecutorProvider() {
return executorProvider;
}
} }

View File

@ -0,0 +1,58 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.bukkit.console.executor;
import com.discordsrv.bukkit.BukkitDiscordSRV;
import com.discordsrv.common.command.game.executor.CommandExecutor;
import com.discordsrv.common.command.game.executor.CommandExecutorProvider;
import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
import java.util.function.Consumer;
public class BukkitCommandExecutorProvider implements CommandExecutorProvider {
private static final boolean HAS_PAPER_FORWARDING;
static {
boolean has = false;
try {
has = PaperCommandExecutor.CREATE_COMMAND_SENDER != null;
} catch (Throwable ignored) {}
HAS_PAPER_FORWARDING = has;
}
private final BukkitDiscordSRV discordSRV;
public BukkitCommandExecutorProvider(BukkitDiscordSRV discordSRV) {
this.discordSRV = discordSRV;
}
@Override
public CommandExecutor getConsoleExecutor(Consumer<Component> componentConsumer) {
if (HAS_PAPER_FORWARDING) {
try {
return new PaperCommandExecutor(discordSRV, componentConsumer);
} catch (Throwable ignored) {}
}
CommandSender commandSender = new BukkitCommandExecutorProxy(discordSRV.server().getConsoleSender(), componentConsumer).getProxy();
return new CommandSenderExecutor(discordSRV, commandSender);
}
}

View File

@ -0,0 +1,39 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.bukkit.console.executor;
import com.discordsrv.bukkit.BukkitDiscordSRV;
import com.discordsrv.common.command.game.executor.CommandExecutor;
import org.bukkit.command.CommandSender;
public class CommandSenderExecutor implements CommandExecutor {
private final BukkitDiscordSRV discordSRV;
private final CommandSender commandSender;
public CommandSenderExecutor(BukkitDiscordSRV discordSRV, CommandSender commandSender) {
this.discordSRV = discordSRV;
this.commandSender = commandSender;
}
@Override
public void runCommand(String command) {
discordSRV.scheduler().runOnMainThread(() -> discordSRV.server().dispatchCommand(commandSender, command));
}
}

View File

@ -0,0 +1,49 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.bukkit.console.executor;
import com.discordsrv.bukkit.BukkitDiscordSRV;
import net.kyori.adventure.text.Component;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.function.Consumer;
@SuppressWarnings("JavaLangInvokeHandleSignature") // PaperAPI that is not included at compile accessed via reflection
public class PaperCommandExecutor extends CommandSenderExecutor {
public static final MethodHandle CREATE_COMMAND_SENDER;
static {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle handle = null;
try {
MethodType methodType = MethodType.methodType(CommandSender.class, Consumer.class);
handle = lookup.findVirtual(Server.class, "createCommandSender", methodType);
} catch (Throwable ignored) {}
CREATE_COMMAND_SENDER = handle;
}
public PaperCommandExecutor(BukkitDiscordSRV discordSRV, Consumer<Component> componentConsumer) throws Throwable {
super(discordSRV, (CommandSender) CREATE_COMMAND_SENDER.invoke(componentConsumer));
}
}

View File

@ -0,0 +1,122 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.bukkit.console.executor;
import dev.vankka.dynamicproxy.CallOriginal;
import dev.vankka.dynamicproxy.processor.Original;
import dev.vankka.dynamicproxy.processor.Proxy;
import net.kyori.adventure.platform.bukkit.BukkitComponentSerializer;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
import java.util.function.Consumer;
@Proxy(value = CommandSender.class, className = "BukkitCommandExecutorProxy")
public abstract class BukkitCommandExecutorProxyTemplate implements CommandSender {
@Original
private final CommandSender commandSender;
private final Consumer<Component> componentConsumer;
private Spigot spigot;
public BukkitCommandExecutorProxyTemplate(CommandSender commandSender, Consumer<Component> componentConsumer) {
this.commandSender = commandSender;
this.componentConsumer = componentConsumer;
try {
spigot = new Spigot(commandSender.spigot());
} catch (Throwable ignored) {}
}
@Override
public void sendMessage(@Nullable UUID sender, @NotNull String... messages) {
forwardLegacy(String.join("\n", messages));
CallOriginal.call(sender, messages);
}
@Override
public void sendMessage(@NotNull String... messages) {
forwardLegacy(String.join("\n", messages));
CallOriginal.call((Object) messages);
}
@Override
public void sendMessage(@Nullable UUID sender, @NotNull String message) {
forwardLegacy(message);
CallOriginal.call(sender, message);
}
@Override
public void sendMessage(@NotNull String message) {
forwardLegacy(message);
CallOriginal.call(message);
}
private void forwardLegacy(String legacy) {
componentConsumer.accept(BukkitComponentSerializer.legacy().deserialize(legacy));
}
@Override
public @NotNull CommandSender.Spigot spigot() {
return spigot;
}
@SuppressWarnings("deprecation")
public class Spigot extends CommandSender.Spigot {
private final CommandSender.Spigot spigot;
Spigot(CommandSender.Spigot spigot) {
this.spigot = spigot;
}
@Override
public void sendMessage(@Nullable UUID sender, @NotNull BaseComponent component) {
spigot.sendMessage(sender, component);
forwardBungee(new BaseComponent[] {component});
}
@Override
public void sendMessage(@NotNull BaseComponent component) {
spigot.sendMessage(component);
forwardBungee(new BaseComponent[] {component});
}
@Override
public void sendMessage(@Nullable UUID sender, @NotNull BaseComponent... components) {
spigot.sendMessage(components);
forwardBungee(components);
}
@Override
public void sendMessage(@NotNull BaseComponent... components) {
spigot.sendMessage(components);
forwardBungee(components);
}
private void forwardBungee(BaseComponent[] components) {
componentConsumer.accept(BungeeComponentSerializer.get().deserialize(components));
}
}
}

View File

@ -20,6 +20,8 @@ package com.discordsrv.bungee.console;
import com.discordsrv.bungee.BungeeDiscordSRV; import com.discordsrv.bungee.BungeeDiscordSRV;
import com.discordsrv.bungee.command.game.sender.BungeeCommandSender; import com.discordsrv.bungee.command.game.sender.BungeeCommandSender;
import com.discordsrv.bungee.console.executor.BungeeCommandExecutorProvider;
import com.discordsrv.common.command.game.executor.CommandExecutorProvider;
import com.discordsrv.common.console.Console; import com.discordsrv.common.console.Console;
import com.discordsrv.common.logging.backend.LoggingBackend; import com.discordsrv.common.logging.backend.LoggingBackend;
import com.discordsrv.common.logging.backend.impl.JavaLoggerImpl; import com.discordsrv.common.logging.backend.impl.JavaLoggerImpl;
@ -27,14 +29,21 @@ import com.discordsrv.common.logging.backend.impl.JavaLoggerImpl;
public class BungeeConsole extends BungeeCommandSender implements Console { public class BungeeConsole extends BungeeCommandSender implements Console {
private final LoggingBackend loggingBackend; private final LoggingBackend loggingBackend;
private final BungeeCommandExecutorProvider executorProvider;
public BungeeConsole(BungeeDiscordSRV discordSRV) { public BungeeConsole(BungeeDiscordSRV discordSRV) {
super(discordSRV, discordSRV.proxy().getConsole(), () -> discordSRV.audiences().console()); super(discordSRV, discordSRV.proxy().getConsole(), () -> discordSRV.audiences().console());
this.loggingBackend = JavaLoggerImpl.getRoot(); this.loggingBackend = JavaLoggerImpl.getRoot();
this.executorProvider = new BungeeCommandExecutorProvider(discordSRV);
} }
@Override @Override
public LoggingBackend loggingBackend() { public LoggingBackend loggingBackend() {
return loggingBackend; return loggingBackend;
} }
@Override
public CommandExecutorProvider commandExecutorProvider() {
return executorProvider;
}
} }

View File

@ -0,0 +1,45 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.bungee.console.executor;
import com.discordsrv.bungee.BungeeDiscordSRV;
import com.discordsrv.common.command.game.executor.CommandExecutor;
import net.kyori.adventure.text.Component;
import net.md_5.bungee.api.CommandSender;
import java.util.function.Consumer;
public class BungeeCommandExecutor implements CommandExecutor {
private final BungeeDiscordSRV discordSRV;
private final CommandSender commandSender;
public BungeeCommandExecutor(BungeeDiscordSRV discordSRV, Consumer<Component> componentConsumer) {
this.discordSRV = discordSRV;
this.commandSender = new BungeeCommandExecutorProxy(
discordSRV.proxy().getConsole(),
componentConsumer
).getProxy();
}
@Override
public void runCommand(String command) {
discordSRV.proxy().getPluginManager().dispatchCommand(commandSender, command);
}
}

View File

@ -0,0 +1,40 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.bungee.console.executor;
import com.discordsrv.bungee.BungeeDiscordSRV;
import com.discordsrv.common.command.game.executor.CommandExecutor;
import com.discordsrv.common.command.game.executor.CommandExecutorProvider;
import net.kyori.adventure.text.Component;
import java.util.function.Consumer;
public class BungeeCommandExecutorProvider implements CommandExecutorProvider {
private final BungeeDiscordSRV discordSRV;
public BungeeCommandExecutorProvider(BungeeDiscordSRV discordSRV) {
this.discordSRV = discordSRV;
}
@Override
public CommandExecutor getConsoleExecutor(Consumer<Component> componentConsumer) {
return new BungeeCommandExecutor(discordSRV, componentConsumer);
}
}

View File

@ -0,0 +1,71 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.bungee.console.executor;
import dev.vankka.dynamicproxy.CallOriginal;
import dev.vankka.dynamicproxy.processor.Original;
import dev.vankka.dynamicproxy.processor.Proxy;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.BaseComponent;
import java.util.function.Consumer;
@Proxy(value = CommandSender.class, className = "BungeeCommandExecutorProxy")
public abstract class BungeeCommandExecutorProxyTemplate implements CommandSender {
@Original
private final CommandSender commandSender;
private final Consumer<Component> componentConsumer;
public BungeeCommandExecutorProxyTemplate(CommandSender commandSender, Consumer<Component> componentConsumer) {
this.commandSender = commandSender;
this.componentConsumer = componentConsumer;
}
private void forwardComponent(Component component) {
this.componentConsumer.accept(component);
}
@Override
public void sendMessage(BaseComponent... message) {
CallOriginal.call((Object) message);
forwardComponent(BungeeComponentSerializer.get().deserialize(message));
}
@Override
public void sendMessage(BaseComponent message) {
CallOriginal.call(message);
forwardComponent(BungeeComponentSerializer.get().deserialize(new BaseComponent[]{message}));
}
@Override
public void sendMessage(String message) {
CallOriginal.call(message);
forwardComponent(LegacyComponentSerializer.legacySection().deserialize(message));
}
@Override
public void sendMessages(String... messages) {
CallOriginal.call((Object) messages);
forwardComponent(LegacyComponentSerializer.legacySection().deserialize(String.join("\n", messages)));
}
}

View File

@ -51,6 +51,9 @@ dependencies {
exclude group: 'com.google.errorprone', module: 'error_prone_annotations' exclude group: 'com.google.errorprone', module: 'error_prone_annotations'
} }
// DynamicProxy
runtimeDownloadApi(libs.dynamicproxy)
// Jackson (transitive in :api) // Jackson (transitive in :api)
compileOnlyApi(libs.jackson.databind) compileOnlyApi(libs.jackson.databind)

View File

@ -1,3 +1,4 @@
dependencies { dependencies {
api project(':common') api project(':common')
api project(':common:common-templates')
} }

View File

@ -1,3 +1,4 @@
dependencies { dependencies {
api project(':common') api project(':common')
api project(':common:common-templates')
} }

View File

@ -0,0 +1,24 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.common.command.game.executor;
public interface CommandExecutor {
void runCommand(String command);
}

View File

@ -0,0 +1,29 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.common.command.game.executor;
import net.kyori.adventure.text.Component;
import java.util.function.Consumer;
@FunctionalInterface
public interface CommandExecutorProvider {
CommandExecutor getConsoleExecutor(Consumer<Component> componentConsumer);
}

View File

@ -18,13 +18,14 @@
package com.discordsrv.common.command.game.sender; package com.discordsrv.common.command.game.sender;
import com.discordsrv.common.command.game.executor.CommandExecutor;
import net.kyori.adventure.audience.ForwardingAudience; import net.kyori.adventure.audience.ForwardingAudience;
import net.kyori.adventure.audience.MessageType; import net.kyori.adventure.audience.MessageType;
import net.kyori.adventure.identity.Identity; import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public interface ICommandSender extends ForwardingAudience.Single { public interface ICommandSender extends ForwardingAudience.Single, CommandExecutor {
/** /**
* Sends a message to this {@link ICommandSender} with {@link Identity#nil()}. * Sends a message to this {@link ICommandSender} with {@link Identity#nil()}.
@ -44,6 +45,5 @@ public interface ICommandSender extends ForwardingAudience.Single {
} }
boolean hasPermission(String permission); boolean hasPermission(String permission);
void runCommand(String command);
} }

View File

@ -18,6 +18,7 @@
package com.discordsrv.common.console; package com.discordsrv.common.console;
import com.discordsrv.common.command.game.executor.CommandExecutorProvider;
import com.discordsrv.common.command.game.sender.ICommandSender; import com.discordsrv.common.command.game.sender.ICommandSender;
import com.discordsrv.common.logging.backend.LoggingBackend; import com.discordsrv.common.logging.backend.LoggingBackend;
@ -28,4 +29,6 @@ public interface Console extends ICommandSender {
* @return the {@link LoggingBackend} * @return the {@link LoggingBackend}
*/ */
LoggingBackend loggingBackend(); LoggingBackend loggingBackend();
CommandExecutorProvider commandExecutorProvider();
} }

View File

@ -0,0 +1,3 @@
dependencies {
api project(':common')
}

View File

@ -0,0 +1,121 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.common.command.executor;
import dev.vankka.dynamicproxy.CallOriginal;
import dev.vankka.dynamicproxy.processor.Original;
import dev.vankka.dynamicproxy.processor.Proxy;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.audience.MessageType;
import net.kyori.adventure.identity.Identified;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentLike;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
@Proxy(value = Audience.class, className = "AdventureCommandExecutorProxy")
public abstract class AdventureCommandExecutorProxyTemplate implements Audience {
@Original
private final Audience audience;
private final Consumer<Component> componentConsumer;
public AdventureCommandExecutorProxyTemplate(Audience audience, Consumer<Component> componentConsumer) {
this.audience = audience;
this.componentConsumer = componentConsumer;
}
private void forwardComponent(ComponentLike component) {
componentConsumer.accept(component.asComponent());
}
@Override
public void sendMessage(@NotNull Identified source, @NotNull ComponentLike message, @NotNull MessageType type) {
CallOriginal.call(source, message, type);
forwardComponent(message);
}
@Override
public void sendMessage(@NotNull Identity source, @NotNull ComponentLike message, @NotNull MessageType type) {
CallOriginal.call(source, message, type);
forwardComponent(message);
}
@Override
public void sendMessage(@NotNull Identified source, @NotNull Component message, @NotNull MessageType type) {
CallOriginal.call(source, message, type);
forwardComponent(message);
}
@Override
public void sendMessage(@NotNull Identity source, @NotNull Component message, @NotNull MessageType type) {
CallOriginal.call(source, message, type);
forwardComponent(message);
}
@Override
public void sendMessage(@NotNull Identified source, @NotNull ComponentLike message) {
CallOriginal.call(source, message);
forwardComponent(message);
}
@Override
public void sendMessage(@NotNull Component message) {
CallOriginal.call(message);
forwardComponent(message);
}
@Override
public void sendMessage(@NotNull ComponentLike message) {
CallOriginal.call(message);
forwardComponent(message);
}
@Override
public void sendMessage(@NotNull Identity source, @NotNull Component message) {
CallOriginal.call(source, message);
forwardComponent(message);
}
@Override
public void sendMessage(@NotNull Component message, @NotNull MessageType type) {
CallOriginal.call(message, type);
forwardComponent(message);
}
@Override
public void sendMessage(@NotNull Identified source, @NotNull Component message) {
CallOriginal.call(source, message);
forwardComponent(message);
}
@Override
public void sendMessage(@NotNull Identity source, @NotNull ComponentLike message) {
CallOriginal.call(source, message);
forwardComponent(message);
}
@Override
public void sendMessage(@NotNull ComponentLike message, @NotNull MessageType type) {
CallOriginal.call(message, type);
forwardComponent(message);
}
}

View File

@ -71,6 +71,9 @@ dependencyResolutionManagement {
reject '[3,)' // Java 11 reject '[3,)' // Java 11
} }
// DynamicProxy
library('dynamicproxy', 'dev.vankka', 'dynamicproxy').version('1.0.0-SNAPSHOT')
// Jackson // Jackson
library('jackson-databind', 'com.fasterxml.jackson.core', 'jackson-databind').version('2.10.1') library('jackson-databind', 'com.fasterxml.jackson.core', 'jackson-databind').version('2.10.1')
@ -131,7 +134,7 @@ dependencyResolutionManagement {
rootProject.name = 'DiscordSRV2' rootProject.name = 'DiscordSRV2'
[ [
'common', 'common:api', 'common:server', 'common:proxy', 'common:unrelocate', 'common', 'common:api', 'common:server', 'common:proxy', 'common:unrelocate', 'common:templates',
'i18n', 'i18n',
'api', 'api',
'bukkit', 'bukkit:loader', 'bukkit', 'bukkit:loader',

View File

@ -18,23 +18,32 @@
package com.discordsrv.sponge.console; package com.discordsrv.sponge.console;
import com.discordsrv.common.command.game.executor.CommandExecutorProvider;
import com.discordsrv.common.console.Console; import com.discordsrv.common.console.Console;
import com.discordsrv.common.logging.backend.LoggingBackend; import com.discordsrv.common.logging.backend.LoggingBackend;
import com.discordsrv.common.logging.backend.impl.Log4JLoggerImpl; import com.discordsrv.common.logging.backend.impl.Log4JLoggerImpl;
import com.discordsrv.sponge.SpongeDiscordSRV; import com.discordsrv.sponge.SpongeDiscordSRV;
import com.discordsrv.sponge.command.game.sender.SpongeCommandSender; import com.discordsrv.sponge.command.game.sender.SpongeCommandSender;
import com.discordsrv.sponge.console.executor.SpongeCommandExecutorProvider;
public class SpongeConsole extends SpongeCommandSender implements Console { public class SpongeConsole extends SpongeCommandSender implements Console {
private final LoggingBackend loggingBackend; private final LoggingBackend loggingBackend;
private final SpongeCommandExecutorProvider executorProvider;
public SpongeConsole(SpongeDiscordSRV discordSRV) { public SpongeConsole(SpongeDiscordSRV discordSRV) {
super(discordSRV, () -> discordSRV.game().systemSubject(), () -> discordSRV.game().systemSubject()); super(discordSRV, () -> discordSRV.game().systemSubject(), () -> discordSRV.game().systemSubject());
this.loggingBackend = Log4JLoggerImpl.getRoot(); this.loggingBackend = Log4JLoggerImpl.getRoot();
this.executorProvider = new SpongeCommandExecutorProvider(discordSRV);
} }
@Override @Override
public LoggingBackend loggingBackend() { public LoggingBackend loggingBackend() {
return loggingBackend; return loggingBackend;
} }
@Override
public CommandExecutorProvider commandExecutorProvider() {
return executorProvider;
}
} }

View File

@ -0,0 +1,58 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.sponge.console.executor;
import com.discordsrv.common.command.executor.AdventureCommandExecutorProxy;
import com.discordsrv.common.command.game.executor.CommandExecutor;
import com.discordsrv.sponge.SpongeDiscordSRV;
import net.kyori.adventure.text.Component;
import org.spongepowered.api.SystemSubject;
import org.spongepowered.api.command.exception.CommandException;
import java.util.function.Consumer;
public class SpongeCommandExecutor implements CommandExecutor {
private final SpongeDiscordSRV discordSRV;
private final SystemSubject subject;
public SpongeCommandExecutor(SpongeDiscordSRV discordSRV, Consumer<Component> componentConsumer) {
this.discordSRV = discordSRV;
this.subject = (SystemSubject) new AdventureCommandExecutorProxy(
discordSRV.game().systemSubject(),
componentConsumer
).getProxy();
}
@Override
public void runCommand(String command) {
discordSRV.scheduler().runOnMainThread(() -> runOnMain(command));
}
private void runOnMain(String command) {
try {
discordSRV.game().server().commandManager().process(subject, command);
} catch (CommandException e) {
Component message = e.componentMessage();
if (message != null) {
subject.sendMessage(message);
}
}
}
}

View File

@ -0,0 +1,40 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.sponge.console.executor;
import com.discordsrv.common.command.game.executor.CommandExecutor;
import com.discordsrv.common.command.game.executor.CommandExecutorProvider;
import com.discordsrv.sponge.SpongeDiscordSRV;
import net.kyori.adventure.text.Component;
import java.util.function.Consumer;
public class SpongeCommandExecutorProvider implements CommandExecutorProvider {
private final SpongeDiscordSRV discordSRV;
public SpongeCommandExecutorProvider(SpongeDiscordSRV discordSRV) {
this.discordSRV = discordSRV;
}
@Override
public CommandExecutor getConsoleExecutor(Consumer<Component> componentConsumer) {
return new SpongeCommandExecutor(discordSRV, componentConsumer);
}
}

View File

@ -18,23 +18,32 @@
package com.discordsrv.velocity.console; package com.discordsrv.velocity.console;
import com.discordsrv.common.command.game.executor.CommandExecutorProvider;
import com.discordsrv.common.console.Console; import com.discordsrv.common.console.Console;
import com.discordsrv.common.logging.backend.LoggingBackend; import com.discordsrv.common.logging.backend.LoggingBackend;
import com.discordsrv.common.logging.backend.impl.Log4JLoggerImpl; import com.discordsrv.common.logging.backend.impl.Log4JLoggerImpl;
import com.discordsrv.velocity.VelocityDiscordSRV; import com.discordsrv.velocity.VelocityDiscordSRV;
import com.discordsrv.velocity.command.game.sender.VelocityCommandSender; import com.discordsrv.velocity.command.game.sender.VelocityCommandSender;
import com.discordsrv.velocity.console.executor.VelocityCommandExecutorProvider;
public class VelocityConsole extends VelocityCommandSender implements Console { public class VelocityConsole extends VelocityCommandSender implements Console {
private final LoggingBackend loggingBackend; private final LoggingBackend loggingBackend;
private final VelocityCommandExecutorProvider executorProvider;
public VelocityConsole(VelocityDiscordSRV discordSRV) { public VelocityConsole(VelocityDiscordSRV discordSRV) {
super(discordSRV, discordSRV.proxy().getConsoleCommandSource()); super(discordSRV, discordSRV.proxy().getConsoleCommandSource());
this.loggingBackend = Log4JLoggerImpl.getRoot(); this.loggingBackend = Log4JLoggerImpl.getRoot();
this.executorProvider = new VelocityCommandExecutorProvider(discordSRV);
} }
@Override @Override
public LoggingBackend loggingBackend() { public LoggingBackend loggingBackend() {
return loggingBackend; return loggingBackend;
} }
@Override
public CommandExecutorProvider commandExecutorProvider() {
return executorProvider;
}
} }

View File

@ -0,0 +1,46 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.velocity.console.executor;
import com.discordsrv.common.command.executor.AdventureCommandExecutorProxy;
import com.discordsrv.common.command.game.executor.CommandExecutor;
import com.discordsrv.velocity.VelocityDiscordSRV;
import com.velocitypowered.api.proxy.ConsoleCommandSource;
import net.kyori.adventure.text.Component;
import java.util.function.Consumer;
public class VelocityCommandExecutor implements CommandExecutor {
private final VelocityDiscordSRV discordSRV;
private final ConsoleCommandSource source;
public VelocityCommandExecutor(VelocityDiscordSRV discordSRV, Consumer<Component> componentConsumer) {
this.discordSRV = discordSRV;
this.source = (ConsoleCommandSource) new AdventureCommandExecutorProxy(
discordSRV.proxy().getConsoleCommandSource(),
componentConsumer
).getProxy();
}
@Override
public void runCommand(String command) {
discordSRV.proxy().getCommandManager().executeAsync(source, command);
}
}

View File

@ -0,0 +1,40 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.velocity.console.executor;
import com.discordsrv.common.command.game.executor.CommandExecutor;
import com.discordsrv.common.command.game.executor.CommandExecutorProvider;
import com.discordsrv.velocity.VelocityDiscordSRV;
import net.kyori.adventure.text.Component;
import java.util.function.Consumer;
public class VelocityCommandExecutorProvider implements CommandExecutorProvider {
private final VelocityDiscordSRV discordSRV;
public VelocityCommandExecutorProvider(VelocityDiscordSRV discordSRV) {
this.discordSRV = discordSRV;
}
@Override
public CommandExecutor getConsoleExecutor(Consumer<Component> componentConsumer) {
return new VelocityCommandExecutor(discordSRV, componentConsumer);
}
}