Initial work. A FAT JAR that doesn't work. Runs via gradle task fabric:runServer.

This commit is contained in:
IxPrumxI 2025-01-12 11:15:05 +03:00
parent 312159e9ec
commit be9c79ee2e
27 changed files with 1155 additions and 3 deletions

View File

@ -8,6 +8,7 @@ plugins {
alias(libs.plugins.run.paper) apply false
alias(libs.plugins.run.waterfall) apply false
alias(libs.plugins.run.velocity) apply false
alias(libs.plugins.fabric.loom) apply false
}
version '3.0.0-SNAPSHOT'

View File

@ -69,6 +69,15 @@
// Webhooks
'club.minnced',
'org.json',
// Fabric,
'net.minecraft',
'com.mojang',
'me.lucko.fabric.api.permissions',
'net.kyori.adventure.platform.modcommon',
'org.spongepowered.asm',
'com.llamalad7.mixinextras',
].each {
tasks.shadowJar.relocate it, 'com.discordsrv.dependencies.' + it
tasks.generateRuntimeDownloadResourceForRuntimeDownloadOnly.relocate it, 'com.discordsrv.dependencies.' + it

80
fabric/build.gradle Normal file
View File

@ -0,0 +1,80 @@
apply from: rootProject.file('buildscript/standalone.gradle')
apply plugin: 'fabric-loom'
configurations.all {
resolutionStrategy {
force "org.slf4j:slf4j-api:1.7.36" // Introduced by Minecraft itself
}
}
java {
disableAutoTargetJvm() // Requires Java 21, we target 8
}
processResources {
filesMatching('**/fabric.mod.json') {
expand 'VERSION': project.version, 'MINECRAFT_VERSION': libs.fabric.minecraft.get().version, 'LOADER_VERSION': libs.fabric.loader.get().version
}
}
shadowJar {
archiveBaseName = 'DiscordSRV-Fabric'
mergeServiceFiles()
}
loom {
serverOnlyMinecraftJar()
}
repositories {
exclusiveContent {
forRepository {
maven { url 'https://maven.fabricmc.net/' }
}
filter {
includeGroup 'net.fabricmc'
}
}
}
dependencies {
// To change the versions see the settings.gradle file
minecraft(libs.fabric.minecraft)
mappings(variantOf(libs.fabric.yarn) { classifier("v2") })
compileOnly(libs.fabric.loader)
modImplementation(libs.fabric.api)
// API
annotationProcessor project(':api')
implementation project(':common:common-api')
// Common
implementation project(':common')
// Adventure
modImplementation(libs.adventure.platform.fabric)
// DependencyDownload
modImplementation(libs.mcdependencydownload.fabric)
// Permission API
modImplementation(libs.fabric.permissions.api)
// Relaying on runtime download to bring these isn't working
implementation(libs.configurate.yaml)
implementation(libs.caffeine)
implementation(libs.mcdiscordreserializer)
implementation(libs.enhancedlegacytext)
implementation(libs.minecraftauth.lib)
// Database
implementation(libs.hikaricp)
implementation(libs.h2)
implementation(libs.mysql)
implementation(libs.mariadb)
// Workaround for https://github.com/FabricMC/fabric-loom/issues/1020.
// The above plugin version workaround can introduce issues like this,
// where versions mismatch due to the inclusion of the plugins as libraries rather than pure plugins.
constraints {implementation("com.google.code.gson:gson:2.8.6")}
}

View File

@ -0,0 +1,112 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric;
import com.discordsrv.common.abstraction.bootstrap.IBootstrap;
import com.discordsrv.common.abstraction.bootstrap.LifecycleManager;
import com.discordsrv.common.core.logging.Logger;
import com.discordsrv.common.core.logging.backend.impl.Log4JLoggerImpl;
import dev.vankka.dependencydownload.classpath.ClasspathAppender;
import dev.vankka.mcdependencydownload.fabric.classpath.FabricClasspathAppender;
import net.fabricmc.api.DedicatedServerModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.GameVersion;
import net.minecraft.MinecraftVersion;
import net.minecraft.server.MinecraftServer;
import org.apache.logging.log4j.LogManager;
import java.io.IOException;
import java.nio.file.Path;
public class DiscordSRVFabricBootstrap implements DedicatedServerModInitializer, IBootstrap {
private final Logger logger;
private final ClasspathAppender classpathAppender;
private final LifecycleManager lifecycleManager;
private MinecraftServer minecraftServer;
private final Path dataDirectory;
private FabricDiscordSRV discordSRV;
public DiscordSRVFabricBootstrap() {
this.logger = new Log4JLoggerImpl(LogManager.getLogger("DiscordSRV"));
this.classpathAppender = new FabricClasspathAppender();
this.dataDirectory = FabricLoader.getInstance().getConfigDir().resolve("DiscordSRV");
try {
this.lifecycleManager = new LifecycleManager(
this.logger,
dataDirectory,
new String[] {"dependencies/runtimeDownload-fabric.txt"},
classpathAppender
);
} catch (IOException e) {
throw new RuntimeException(e);
}
this.minecraftServer = null;
}
@Override
public void onInitializeServer() {
ServerLifecycleEvents.SERVER_STARTED.register(minecraftServer -> {
this.minecraftServer = minecraftServer;
lifecycleManager.loadAndEnable(() -> this.discordSRV = new FabricDiscordSRV(this));
discordSRV.runEnable();
this.discordSRV.runServerStarted();
});
}
@Override
public Logger logger() {
return logger;
}
@Override
public ClasspathAppender classpathAppender() {
return classpathAppender;
}
@Override
public ClassLoader classLoader() {
return getClass().getClassLoader();
}
@Override
public LifecycleManager lifecycleManager() {
return lifecycleManager;
}
@Override
public Path dataDirectory() {
return dataDirectory;
}
@Override
public String platformVersion() {
GameVersion version = MinecraftVersion.CURRENT;
return version.getName() + " (from Fabric)"; //TODO: get current build version for Fabric
}
public MinecraftServer getServer() {
return minecraftServer;
}
public FabricDiscordSRV getDiscordSRV() {
return discordSRV;
}
}

View File

@ -0,0 +1,158 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric;
import com.discordsrv.common.config.configurate.manager.ConnectionConfigManager;
import com.discordsrv.common.config.configurate.manager.MainConfigManager;
import com.discordsrv.common.config.configurate.manager.MessagesConfigManager;
import com.discordsrv.common.config.messages.MessagesConfig;
import com.discordsrv.common.feature.messageforwarding.game.MinecraftToDiscordChatModule;
import com.discordsrv.fabric.config.connection.FabricConnectionConfig;
import com.discordsrv.fabric.config.main.FabricConfig;
import com.discordsrv.fabric.config.manager.FabricConfigManager;
import com.discordsrv.fabric.config.manager.FabricConnectionConfigManager;
import com.discordsrv.fabric.config.manager.FabricMessagesConfigManager;
import com.discordsrv.fabric.console.FabricConsole;
import com.discordsrv.fabric.game.handler.FabricCommandHandler;
import com.discordsrv.fabric.listener.FabricChatListener;
import com.discordsrv.fabric.player.FabricPlayerProvider;
import com.discordsrv.fabric.plugin.FabricModManager;
import com.discordsrv.common.AbstractDiscordSRV;
import com.discordsrv.common.abstraction.plugin.PluginManager;
import com.discordsrv.common.command.game.abstraction.handler.ICommandHandler;
import com.discordsrv.common.core.scheduler.StandardScheduler;
import com.discordsrv.common.feature.debug.data.OnlineMode;
import net.minecraft.server.MinecraftServer;
import org.jetbrains.annotations.NotNull;
import java.net.URL;
import java.util.jar.JarFile;
public class FabricDiscordSRV extends AbstractDiscordSRV<DiscordSRVFabricBootstrap, FabricConfig, FabricConnectionConfig, MessagesConfig> {
private final StandardScheduler scheduler;
private final FabricConsole console;
private final FabricPlayerProvider playerProvider;
private final FabricModManager modManager;
private final FabricCommandHandler commandHandler;
private final FabricConnectionConfigManager connectionConfigManager;
private final FabricConfigManager configManager;
private final FabricMessagesConfigManager messagesConfigManager;
public FabricDiscordSRV(DiscordSRVFabricBootstrap bootstrap) {
super(bootstrap);
this.scheduler = new StandardScheduler(this);
this.console = new FabricConsole(this);
this.playerProvider = new FabricPlayerProvider(this);
this.modManager = new FabricModManager(this);
this.commandHandler = new FabricCommandHandler(this);
// Config
this.connectionConfigManager = new FabricConnectionConfigManager(this);
this.configManager = new FabricConfigManager(this);
this.messagesConfigManager = new FabricMessagesConfigManager(this);
registerEvents();
load();
}
private void registerEvents() {
new FabricChatListener(this);
registerModule(MinecraftToDiscordChatModule::new);
}
//TODO: Implement this method. Maybe with KnotClassloader?
@Override
protected URL getManifest() {
ClassLoader classLoader = getClass().getClassLoader();
return classLoader.getResource(JarFile.MANIFEST_NAME);
// if (classLoader instanceof URLClassLoader) {
// return ((URLClassLoader) classLoader).findResource(JarFile.MANIFEST_NAME);
// } else {
// throw new IllegalStateException("Class not loaded by a URLClassLoader, unable to get manifest");
// }
}
public FabricModManager getModManager() {
return modManager;
}
public MinecraftServer getServer() {
return bootstrap.getServer();
}
@Override
public ServerType serverType() {
return ServerType.SERVER;
}
@Override
public StandardScheduler scheduler() {
return scheduler;
}
@Override
public FabricConsole console() {
return console;
}
@Override
public @NotNull FabricPlayerProvider playerProvider() {
return playerProvider;
}
@Override
public PluginManager pluginManager() {
return modManager;
}
@Override
public OnlineMode onlineMode() {
return OnlineMode.of(getServer().isOnlineMode());
}
@Override
public ICommandHandler commandHandler() {
return commandHandler;
}
@Override
public ConnectionConfigManager<FabricConnectionConfig> connectionConfigManager() {
return connectionConfigManager;
}
@Override
public MainConfigManager<FabricConfig> configManager() {
return configManager;
}
@Override
public MessagesConfigManager<MessagesConfig> messagesConfigManager() {
return messagesConfigManager;
}
@Override
protected void enable() throws Throwable {
super.enable();
}
}

View File

@ -0,0 +1,27 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric.config.connection;
import com.discordsrv.common.config.connection.ConnectionConfig;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
@ConfigSerializable
public class FabricConnectionConfig extends ConnectionConfig {
}

View File

@ -0,0 +1,49 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric.config.main;
import com.discordsrv.common.config.configurate.annotation.Order;
import com.discordsrv.common.config.main.MainConfig;
import com.discordsrv.common.config.main.PresenceUpdaterConfig;
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
import com.discordsrv.common.config.main.channels.base.server.ServerBaseChannelConfig;
import com.discordsrv.common.config.main.channels.base.server.ServerChannelConfig;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
@ConfigSerializable
public class FabricConfig extends MainConfig {
@Override
public BaseChannelConfig createDefaultBaseChannel() {
return new ServerBaseChannelConfig();
}
@Override
public BaseChannelConfig createDefaultChannel() {
return new ServerChannelConfig();
}
@Order(5)
public FabricRequiredLinkingConfig requiredLinking = new FabricRequiredLinkingConfig();
@Override
public PresenceUpdaterConfig defaultPresenceUpdater() {
return new PresenceUpdaterConfig.Server();
}
}

View File

@ -0,0 +1,40 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric.config.main;
import com.discordsrv.common.config.main.linking.ServerRequiredLinkingConfig;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
import org.spongepowered.configurate.objectmapping.meta.Comment;
public class FabricRequiredLinkingConfig extends ServerRequiredLinkingConfig {
public KickOptions kick = new KickOptions();
@ConfigSerializable
public static class KickOptions {
@Comment("The event to use for kick.\n"
+ "Available events: AsyncPlayerPreLoginEvent (preferred), PlayerLoginEvent, PlayerJoinEvent")
public String event = "AsyncPlayerPreLoginEvent";
@Comment("The event priority to use for the kick")
public String priority = "NORMAL";
}
}

View File

@ -0,0 +1,41 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric.config.manager;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.configurate.manager.abstraction.ServerConfigManager;
import com.discordsrv.fabric.config.main.FabricConfig;
import java.nio.file.Path;
public class FabricConfigManager extends ServerConfigManager<FabricConfig> {
public FabricConfigManager(DiscordSRV discordSRV) {
super(discordSRV);
}
public FabricConfigManager(Path dataDirectory) {
super(dataDirectory);
}
@Override
public FabricConfig createConfiguration() {
return new FabricConfig();
}
}

View File

@ -0,0 +1,42 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric.config.manager;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.configurate.manager.ConnectionConfigManager;
import com.discordsrv.fabric.config.connection.FabricConnectionConfig;
import java.nio.file.Path;
public class FabricConnectionConfigManager extends ConnectionConfigManager<FabricConnectionConfig> {
public FabricConnectionConfigManager(DiscordSRV discordSRV) {
super(discordSRV);
}
public FabricConnectionConfigManager(Path dataDirectory) {
super(dataDirectory);
}
@Override
public FabricConnectionConfig createConfiguration() {
return new FabricConnectionConfig();
}
}

View File

@ -0,0 +1,35 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric.config.manager;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.configurate.manager.MessagesConfigManager;
import com.discordsrv.common.config.messages.MessagesConfig;
public class FabricMessagesConfigManager extends MessagesConfigManager<MessagesConfig> {
public FabricMessagesConfigManager(DiscordSRV discordSRV) {
super(discordSRV);
}
@Override
public MessagesConfig createConfiguration() {
return new MessagesConfig();
}
}

View File

@ -0,0 +1,49 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric.console;
import com.discordsrv.fabric.FabricDiscordSRV;
import com.discordsrv.fabric.console.executor.FabricCommandExecutorProvider;
import com.discordsrv.fabric.game.sender.FabricCommandSender;
import com.discordsrv.common.command.game.abstraction.executor.CommandExecutorProvider;
import com.discordsrv.common.core.logging.backend.LoggingBackend;
import com.discordsrv.common.core.logging.backend.impl.Log4JLoggerImpl;
import com.discordsrv.common.feature.console.Console;
public class FabricConsole extends FabricCommandSender implements Console {
private final LoggingBackend loggingBackend;
private final FabricCommandExecutorProvider executorProvider;
public FabricConsole(FabricDiscordSRV discordSRV) {
super(discordSRV, discordSRV.getServer().getCommandSource());
this.loggingBackend = Log4JLoggerImpl.getRoot();
this.executorProvider = new FabricCommandExecutorProvider(discordSRV);
}
@Override
public LoggingBackend 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-2025 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.fabric.console.executor;
import com.discordsrv.fabric.FabricDiscordSRV;
import com.discordsrv.common.command.game.abstraction.executor.AdventureCommandExecutorProxy;
import com.discordsrv.common.command.game.abstraction.executor.CommandExecutor;
import net.kyori.adventure.text.Component;
import net.minecraft.server.command.ServerCommandSource;
import java.util.function.Consumer;
public class FabricCommandExecutor implements CommandExecutor {
private final FabricDiscordSRV discordSRV;
private final ServerCommandSource source;
public FabricCommandExecutor(FabricDiscordSRV discordSRV, Consumer<Component> componentConsumer) {
this.discordSRV = discordSRV;
this.source = (ServerCommandSource) new AdventureCommandExecutorProxy(
discordSRV.getServer().getCommandSource(),
componentConsumer
).getProxy();
}
@Override
public void runCommand(String command) {
discordSRV.getServer().getCommandManager().executeWithPrefix(source, command);
}
}

View File

@ -0,0 +1,40 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric.console.executor;
import com.discordsrv.fabric.FabricDiscordSRV;
import com.discordsrv.common.command.game.abstraction.executor.CommandExecutor;
import com.discordsrv.common.command.game.abstraction.executor.CommandExecutorProvider;
import net.kyori.adventure.text.Component;
import java.util.function.Consumer;
public class FabricCommandExecutorProvider implements CommandExecutorProvider {
private final FabricDiscordSRV discordSRV;
public FabricCommandExecutorProvider(FabricDiscordSRV discordSRV) {
this.discordSRV = discordSRV;
}
@Override
public CommandExecutor getConsoleExecutor(Consumer<Component> componentConsumer) {
return new FabricCommandExecutor(discordSRV, componentConsumer);
}
}

View File

@ -0,0 +1,54 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric.game.handler;
import com.discordsrv.fabric.FabricDiscordSRV;
import com.discordsrv.common.command.game.abstraction.command.GameCommand;
import com.discordsrv.common.command.game.abstraction.handler.ICommandHandler;
import com.discordsrv.common.command.game.abstraction.handler.util.BrigadierUtil;
import com.discordsrv.common.command.game.abstraction.sender.ICommandSender;
import com.mojang.brigadier.tree.LiteralCommandNode;
import net.minecraft.command.CommandSource;
import net.minecraft.server.command.ServerCommandSource;
public class FabricCommandHandler implements ICommandHandler {
private final FabricDiscordSRV discordSRV;
public FabricCommandHandler(FabricDiscordSRV discordSRV) {
this.discordSRV = discordSRV;
}
private ICommandSender getSender(CommandSource source) {
if (source instanceof ServerCommandSource) {
if (((ServerCommandSource) source).getPlayer() != null) {
return discordSRV.playerProvider().player(((ServerCommandSource) source).getPlayer());
} else {
return discordSRV.console();
}
}
return null;
}
@Override
public void registerCommand(GameCommand command) {
LiteralCommandNode<ServerCommandSource> node = BrigadierUtil.convertToBrigadier(command, this::getSender);
discordSRV.getServer().getCommandManager().getDispatcher().getRoot().addChild(node);
}
}

View File

@ -0,0 +1,53 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric.game.sender;
import com.discordsrv.fabric.FabricDiscordSRV;
import com.discordsrv.common.command.game.abstraction.sender.ICommandSender;
import me.lucko.fabric.api.permissions.v0.Permissions;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences;
import net.minecraft.server.command.ServerCommandSource;
import org.jetbrains.annotations.NotNull;
public class FabricCommandSender implements ICommandSender {
protected final FabricDiscordSRV discordSRV;
protected final ServerCommandSource commandSource;
public FabricCommandSender(FabricDiscordSRV discordSRV, ServerCommandSource commandSource) {
this.discordSRV = discordSRV;
this.commandSource = commandSource;
}
@Override
public boolean hasPermission(String permission) {
return Permissions.check(commandSource, permission);
}
@Override
public void runCommand(String command) {
discordSRV.getServer().getCommandManager().executeWithPrefix(commandSource, command);
}
@Override
public @NotNull Audience audience() {
return MinecraftServerAudiences.of(discordSRV.getServer()).audience(commandSource);
}
}

View File

@ -0,0 +1,34 @@
package com.discordsrv.fabric.listener;
import com.discordsrv.api.component.MinecraftComponent;
import com.discordsrv.api.events.message.receive.game.GameChatMessageReceiveEvent;
import com.discordsrv.common.feature.channel.global.GlobalChannel;
import com.discordsrv.fabric.FabricDiscordSRV;
import net.fabricmc.fabric.api.message.v1.ServerMessageEvents;
import net.kyori.adventure.text.Component;
import net.minecraft.network.message.MessageType;
import net.minecraft.network.message.SignedMessage;
import net.minecraft.server.network.ServerPlayerEntity;
public class FabricChatListener {
private final FabricDiscordSRV discordSRV;
public FabricChatListener(FabricDiscordSRV discordSRV) {
this.discordSRV = discordSRV;
ServerMessageEvents.CHAT_MESSAGE.register(this::onChatMessage);
}
private void onChatMessage(SignedMessage signedMessage, ServerPlayerEntity serverPlayerEntity, MessageType.Parameters parameters) {
Component component = discordSRV.componentFactory().parse(signedMessage.getSignedContent());
discordSRV.eventBus().publish(new GameChatMessageReceiveEvent(
null,
discordSRV.playerProvider().player(serverPlayerEntity),
MinecraftComponent.fromAdventure((com.discordsrv.unrelocate.net.kyori.adventure.text.Component) component),
new GlobalChannel(discordSRV),
false
));
}
}

View File

@ -0,0 +1,103 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric.player;
import com.discordsrv.fabric.FabricDiscordSRV;
import com.discordsrv.fabric.game.sender.FabricCommandSender;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.abstraction.player.IPlayer;
import com.discordsrv.common.abstraction.player.provider.model.SkinInfo;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
public class FabricPlayer extends FabricCommandSender implements IPlayer {
private final ServerPlayerEntity player;
public FabricPlayer(FabricDiscordSRV discordSRV, ServerPlayerEntity player) {
super(discordSRV, player.getCommandSource());
this.player = player;
}
@Override
public DiscordSRV discordSRV() {
return discordSRV;
}
@Override
public @NotNull String username() {
return player.getName().getString();
}
@Override
public @Nullable Locale locale() {
return Locale.of(player.getClientOptions().language());
}
@Override
public CompletableFuture<Void> kick(Component component) {
player.networkHandler.disconnect(Text.of(component.toString()));
return CompletableFuture.completedFuture(null);
}
@Override
public void addChatSuggestions(Collection<String> suggestions) {
// API not available in Fabric
}
@Override
public void removeChatSuggestions(Collection<String> suggestions) {
// API not available in Fabric
}
@Override
public @Nullable SkinInfo skinInfo() {
// Unimplemented
return null;
}
@Override
public @NotNull Identity identity() {
return player.identity();
}
@Override
public @NotNull Component displayName() {
// Use Adventure's Pointer, otherwise username
return player.getOrDefaultFrom(
Identity.DISPLAY_NAME,
() -> Component.text(player.getName().getString())
);
}
@Override
public String toString() {
return "FabricPlayer{" + username() + "}";
}
}

View File

@ -0,0 +1,72 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric.player;
import com.discordsrv.fabric.FabricDiscordSRV;
import com.discordsrv.common.abstraction.player.provider.AbstractPlayerProvider;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
public class FabricPlayerProvider extends AbstractPlayerProvider<FabricPlayer, FabricDiscordSRV> {
public FabricPlayerProvider(FabricDiscordSRV discordSRV) {
super(discordSRV);
// Register events here instead of in subscribe() to avoid duplicate registrations. Since there's no unregister method for events in Fabric, we need to make sure we only register once.
ServerPlayConnectionEvents.JOIN.register(this::onConnection);
ServerPlayConnectionEvents.DISCONNECT.register(this::onDisconnect);
}
@Override
public void subscribe() {
// Add players that are already connected
for (ServerPlayerEntity player : discordSRV.getServer().getPlayerManager().getPlayerList()) {
addPlayer(player, true);
}
}
@Override
public void unsubscribe() {
for (ServerPlayerEntity player : discordSRV.getServer().getPlayerManager().getPlayerList()) {
removePlayer(player.getUuid());
}
}
private void onConnection(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSender packetSender, MinecraftServer minecraftServer) {
addPlayer(serverPlayNetworkHandler.player, false);
}
private void onDisconnect(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) {
removePlayer(serverPlayNetworkHandler.player.getUuid());
}
private void addPlayer(ServerPlayerEntity player, boolean initial) {
addPlayer(player.getUuid(), new FabricPlayer(discordSRV, player), initial);
}
public FabricPlayer player(ServerPlayerEntity player) {
FabricPlayer srvPlayer = player(player.getUuid());
if (srvPlayer == null) {
throw new IllegalStateException("Player not available");
}
return srvPlayer;
}
}

View File

@ -0,0 +1,58 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 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.fabric.plugin;
import com.discordsrv.fabric.FabricDiscordSRV;
import com.discordsrv.common.abstraction.plugin.Plugin;
import com.discordsrv.common.abstraction.plugin.PluginManager;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.metadata.Person;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
public class FabricModManager implements PluginManager {
private final FabricDiscordSRV discordSRV;
public FabricModManager(FabricDiscordSRV discordSRV) {
this.discordSRV = discordSRV;
}
@Override
public boolean isPluginEnabled(String modIdentifier) {
return FabricLoader.getInstance().isModLoaded(modIdentifier.toLowerCase(Locale.ROOT));
}
@Override
public List<Plugin> getPlugins() {
return FabricLoader.getInstance().getAllMods().stream()
.map(modContainer -> {
String id = modContainer.getMetadata().getId();
return new Plugin(
id,
modContainer.getMetadata().getName(),
modContainer.getMetadata().getVersion().toString(),
modContainer.getMetadata().getAuthors().stream().map(Person::getName).collect(Collectors.toList())
);
})
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,28 @@
{
"schemaVersion": 1,
"id": "discordsrv",
"version": "${VERSION}",
"name": "DiscordSRV",
"description": "",
"authors": [],
"contact": {},
"license": "All-Rights-Reserved",
"environment": "server",
"entrypoints": {
"server": [
"com.discordsrv.fabric.DiscordSRVFabricBootstrap"
]
},
"mixins": [],
"jars": [
{
"file": "META-INF/jars/adventure-platform-mod-shared-fabric-repack-6.1.0.jar"
}
],
"depends": {
"fabricloader": ">=${LOADER_VERSION}",
"fabric": "*",
"minecraft": "${MINECRAFT_VERSION}",
"fabric-permissions-api-v0": "*"
}
}

View File

@ -1,2 +1,3 @@
# Lower compile time by parallelizing the build
org.gradle.parallel=true
org.gradle.jvmargs=-Xmx4096M

Binary file not shown.

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

5
gradlew vendored
View File

@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

2
gradlew.bat vendored
View File

@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################

View File

@ -1,7 +1,9 @@
pluginManagement {
repositories {
mavenLocal()
mavenCentral() // for slf4j
maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
maven { url 'https://maven.fabricmc.net/'}
gradlePluginPortal()
}
}
@ -40,6 +42,15 @@ dependencyResolutionManagement {
// Velocity
library('velocity', 'com.velocitypowered', 'velocity-api').version('3.3.0-SNAPSHOT')
// Fabric
version('fabric-loom', '1.9-SNAPSHOT')
plugin('fabric-loom', 'fabric-loom').versionRef('fabric-loom')
library('fabric-minecraft', 'com.mojang', 'minecraft').version('1.21.4')
library('fabric-yarn', 'net.fabricmc', 'yarn').version('1.21.4+build.8')
library('fabric-loader', 'net.fabricmc', 'fabric-loader').version('0.16.9')
library('fabric-api', 'net.fabricmc.fabric-api', 'fabric-api').version('0.114.2+1.21.4')
library('fabric-permissions-api', 'me.lucko', 'fabric-permissions-api').version('0.3.3')
// DependencyDownload
version('dependencydownload', '2.0.0-SNAPSHOT')
plugin('dependencydownload-plugin', 'dev.vankka.dependencydownload.plugin').versionRef('dependencydownload')
@ -54,6 +65,7 @@ dependencyResolutionManagement {
library('mcdependencydownload-bungee-bootstrap', 'dev.vankka', 'minecraftdependencydownload-bungee').versionRef('mcdependencydownload')
library('mcdependencydownload-bungee-loader', 'dev.vankka', 'minecraftdependencydownload-bungee-loader').versionRef('mcdependencydownload')
library('mcdependencydownload-velocity', 'dev.vankka', 'minecraftdependencydownload-velocity').versionRef('mcdependencydownload')
library('mcdependencydownload-fabric', 'dev.vankka', 'minecraftdependencydownload-fabric').versionRef('mcdependencydownload')
// Annotations
library('jetbrains-annotations', 'org.jetbrains', 'annotations').version('24.1.0')
@ -132,8 +144,10 @@ dependencyResolutionManagement {
// Adventure Platform
version('adventure-platform', '4.3.4')
version('adventure-platform-mod', '6.2.0')
library('adventure-platform-bukkit', 'net.kyori', 'adventure-platform-bukkit').versionRef('adventure-platform')
library('adventure-platform-bungee', 'net.kyori', 'adventure-platform-bungeecord').versionRef('adventure-platform')
library('adventure-platform-fabric', 'net.kyori', 'adventure-platform-fabric').versionRef('adventure-platform-mod')
library('adventure-serializer-bungee', 'net.kyori', 'adventure-text-serializer-bungeecord').versionRef('adventure-platform')
// Upgrade ansi (used by ansi serializer)
@ -157,7 +171,8 @@ rootProject.name = 'DiscordSRV-Ascension'
'api',
'bukkit', 'bukkit:loader', 'bukkit:folia', 'bukkit:spigot', 'bukkit:paper', 'bukkit:bukkit1_12',
'bungee', 'bungee:loader',
'velocity'
'velocity',
'fabric'
].each {
include it
findProject(':' + it).name = String.join('-', it.split(':'))