From be9c79ee2ec4944403104e6436880f6f1d8c559a Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Sun, 12 Jan 2025 11:15:05 +0300 Subject: [PATCH 01/51] Initial work. A FAT JAR that doesn't work. Runs via gradle task fabric:runServer. --- build.gradle | 1 + buildscript/relocations.gradle | 9 + fabric/build.gradle | 80 +++++++++ .../fabric/DiscordSRVFabricBootstrap.java | 112 +++++++++++++ .../discordsrv/fabric/FabricDiscordSRV.java | 158 ++++++++++++++++++ .../connection/FabricConnectionConfig.java | 27 +++ .../fabric/config/main/FabricConfig.java | 49 ++++++ .../main/FabricRequiredLinkingConfig.java | 40 +++++ .../config/manager/FabricConfigManager.java | 41 +++++ .../FabricConnectionConfigManager.java | 42 +++++ .../manager/FabricMessagesConfigManager.java | 35 ++++ .../fabric/console/FabricConsole.java | 49 ++++++ .../executor/FabricCommandExecutor.java | 46 +++++ .../FabricCommandExecutorProvider.java | 40 +++++ .../game/handler/FabricCommandHandler.java | 54 ++++++ .../game/sender/FabricCommandSender.java | 53 ++++++ .../fabric/listener/FabricChatListener.java | 34 ++++ .../fabric/player/FabricPlayer.java | 103 ++++++++++++ .../fabric/player/FabricPlayerProvider.java | 72 ++++++++ .../fabric/plugin/FabricModManager.java | 58 +++++++ fabric/src/main/resources/fabric.mod.json | 28 ++++ gradle.properties | 1 + gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 5 +- gradlew.bat | 2 + settings.gradle | 17 +- 27 files changed, 1155 insertions(+), 3 deletions(-) create mode 100644 fabric/build.gradle create mode 100644 fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/config/connection/FabricConnectionConfig.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/config/main/FabricConfig.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/config/main/FabricRequiredLinkingConfig.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConfigManager.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConnectionConfigManager.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricMessagesConfigManager.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutorProvider.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/game/handler/FabricCommandHandler.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/game/sender/FabricCommandSender.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/listener/FabricChatListener.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/plugin/FabricModManager.java create mode 100644 fabric/src/main/resources/fabric.mod.json diff --git a/build.gradle b/build.gradle index 15cf3dfd..59e2acea 100644 --- a/build.gradle +++ b/build.gradle @@ -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' diff --git a/buildscript/relocations.gradle b/buildscript/relocations.gradle index e1f65043..99de544b 100644 --- a/buildscript/relocations.gradle +++ b/buildscript/relocations.gradle @@ -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 diff --git a/fabric/build.gradle b/fabric/build.gradle new file mode 100644 index 00000000..ad4d1755 --- /dev/null +++ b/fabric/build.gradle @@ -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")} +} \ No newline at end of file diff --git a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java new file mode 100644 index 00000000..33d56ccc --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java @@ -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 . + */ + +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; + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java new file mode 100644 index 00000000..01f048e9 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java @@ -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 . + */ + +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 { + + 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 connectionConfigManager() { + return connectionConfigManager; + } + + @Override + public MainConfigManager configManager() { + return configManager; + } + + @Override + public MessagesConfigManager messagesConfigManager() { + return messagesConfigManager; + } + + @Override + protected void enable() throws Throwable { + super.enable(); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/config/connection/FabricConnectionConfig.java b/fabric/src/main/java/com/discordsrv/fabric/config/connection/FabricConnectionConfig.java new file mode 100644 index 00000000..59c66cf8 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/config/connection/FabricConnectionConfig.java @@ -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 . + */ + +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 { + +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricConfig.java b/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricConfig.java new file mode 100644 index 00000000..497af748 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricConfig.java @@ -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 . + */ + +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(); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricRequiredLinkingConfig.java b/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricRequiredLinkingConfig.java new file mode 100644 index 00000000..6267d502 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricRequiredLinkingConfig.java @@ -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 . + */ + +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"; + + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConfigManager.java b/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConfigManager.java new file mode 100644 index 00000000..417fdf33 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConfigManager.java @@ -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 . + */ + +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 { + + public FabricConfigManager(DiscordSRV discordSRV) { + super(discordSRV); + } + + public FabricConfigManager(Path dataDirectory) { + super(dataDirectory); + } + + @Override + public FabricConfig createConfiguration() { + return new FabricConfig(); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConnectionConfigManager.java b/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConnectionConfigManager.java new file mode 100644 index 00000000..7ce7ae11 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConnectionConfigManager.java @@ -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 . + */ + +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 { + + public FabricConnectionConfigManager(DiscordSRV discordSRV) { + super(discordSRV); + } + + public FabricConnectionConfigManager(Path dataDirectory) { + super(dataDirectory); + } + + @Override + public FabricConnectionConfig createConfiguration() { + return new FabricConnectionConfig(); + } + +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricMessagesConfigManager.java b/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricMessagesConfigManager.java new file mode 100644 index 00000000..e80ab8df --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricMessagesConfigManager.java @@ -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 . + */ + +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 { + + public FabricMessagesConfigManager(DiscordSRV discordSRV) { + super(discordSRV); + } + + @Override + public MessagesConfig createConfiguration() { + return new MessagesConfig(); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java b/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java new file mode 100644 index 00000000..3e20169c --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java @@ -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 . + */ + +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; + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java new file mode 100644 index 00000000..abe66336 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java @@ -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 . + */ + +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 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); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutorProvider.java b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutorProvider.java new file mode 100644 index 00000000..1c005011 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutorProvider.java @@ -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 . + */ + +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 componentConsumer) { + return new FabricCommandExecutor(discordSRV, componentConsumer); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/game/handler/FabricCommandHandler.java b/fabric/src/main/java/com/discordsrv/fabric/game/handler/FabricCommandHandler.java new file mode 100644 index 00000000..a295fea3 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/game/handler/FabricCommandHandler.java @@ -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 . + */ + +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 node = BrigadierUtil.convertToBrigadier(command, this::getSender); + discordSRV.getServer().getCommandManager().getDispatcher().getRoot().addChild(node); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/game/sender/FabricCommandSender.java b/fabric/src/main/java/com/discordsrv/fabric/game/sender/FabricCommandSender.java new file mode 100644 index 00000000..f03043bb --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/game/sender/FabricCommandSender.java @@ -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 . + */ + +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); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/listener/FabricChatListener.java b/fabric/src/main/java/com/discordsrv/fabric/listener/FabricChatListener.java new file mode 100644 index 00000000..bacddcd6 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/listener/FabricChatListener.java @@ -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 + )); + } + +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java new file mode 100644 index 00000000..0d7d6868 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java @@ -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 . + */ + +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 kick(Component component) { + player.networkHandler.disconnect(Text.of(component.toString())); + return CompletableFuture.completedFuture(null); + } + + @Override + public void addChatSuggestions(Collection suggestions) { + // API not available in Fabric + } + + @Override + public void removeChatSuggestions(Collection 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() + "}"; + } + +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java new file mode 100644 index 00000000..1acd25c8 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java @@ -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 . + */ + +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 { + + 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; + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/plugin/FabricModManager.java b/fabric/src/main/java/com/discordsrv/fabric/plugin/FabricModManager.java new file mode 100644 index 00000000..3671f8c5 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/plugin/FabricModManager.java @@ -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 . + */ + +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 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()); + } +} diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..a490e04d --- /dev/null +++ b/fabric/src/main/resources/fabric.mod.json @@ -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": "*" + } +} diff --git a/gradle.properties b/gradle.properties index 1f0dad2c..77a90b8a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,3 @@ # Lower compile time by parallelizing the build org.gradle.parallel=true +org.gradle.jvmargs=-Xmx4096M diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 12612 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 HJ4oML2Lo<@i8BwbL^1~GkG`E7C$SEa_ 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138..94113f20 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/gradlew b/gradlew index b740cf13..f5feea6d 100755 --- a/gradlew +++ b/gradlew @@ -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 diff --git a/gradlew.bat b/gradlew.bat index 25da30db..9d21a218 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -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 ########################################################################## diff --git a/settings.gradle b/settings.gradle index f8c2a975..c383b63b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -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(':')) From 436f56d0c4966466d880883964394b906dd2e43d Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Sun, 12 Jan 2025 11:43:35 +0300 Subject: [PATCH 02/51] Ignore fabric run folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f6d3010c..5e9e5402 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ hs_err_pid* # run-* Gradle tasks **/loader/run/ **/velocity/run/ +**/fabric/run/ \ No newline at end of file From 78d355491c5a04a2c832956c1e411cf45111adcf Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Sun, 12 Jan 2025 12:00:41 +0300 Subject: [PATCH 03/51] Some work --- .../fabric/DiscordSRVFabricBootstrap.java | 3 +- .../discordsrv/fabric/FabricDiscordSRV.java | 25 ++++++----- .../connection/FabricConnectionConfig.java | 27 ------------ .../fabric/config/main/FabricConfig.java | 3 +- .../main/FabricRequiredLinkingConfig.java | 40 ------------------ .../config/manager/FabricConfigManager.java | 41 ------------------ .../FabricConnectionConfigManager.java | 42 ------------------- .../manager/FabricMessagesConfigManager.java | 35 ---------------- .../fabric/listener/FabricChatListener.java | 36 ++++++++++++---- settings.gradle | 1 - 10 files changed, 43 insertions(+), 210 deletions(-) delete mode 100644 fabric/src/main/java/com/discordsrv/fabric/config/connection/FabricConnectionConfig.java delete mode 100644 fabric/src/main/java/com/discordsrv/fabric/config/main/FabricRequiredLinkingConfig.java delete mode 100644 fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConfigManager.java delete mode 100644 fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConnectionConfigManager.java delete mode 100644 fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricMessagesConfigManager.java diff --git a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java index 33d56ccc..cd614377 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java +++ b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.nio.file.Path; +import java.util.Collections; public class DiscordSRVFabricBootstrap implements DedicatedServerModInitializer, IBootstrap { @@ -52,7 +53,7 @@ public DiscordSRVFabricBootstrap() { this.lifecycleManager = new LifecycleManager( this.logger, dataDirectory, - new String[] {"dependencies/runtimeDownload-fabric.txt"}, + Collections.singletonList("dependencies/runtimeDownload-fabric.txt"), classpathAppender ); } catch (IOException e) { diff --git a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java index 01f048e9..b4a412fe 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java +++ b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java @@ -21,13 +21,11 @@ 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.configurate.manager.abstraction.ServerConfigManager; +import com.discordsrv.common.config.connection.ConnectionConfig; 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; @@ -44,7 +42,7 @@ import java.net.URL; import java.util.jar.JarFile; -public class FabricDiscordSRV extends AbstractDiscordSRV { +public class FabricDiscordSRV extends AbstractDiscordSRV { private final StandardScheduler scheduler; private final FabricConsole console; @@ -52,9 +50,9 @@ public class FabricDiscordSRV extends AbstractDiscordSRV connectionConfigManager; + private final MainConfigManager configManager; + private final MessagesConfigManager messagesConfigManager; public FabricDiscordSRV(DiscordSRVFabricBootstrap bootstrap) { super(bootstrap); @@ -66,12 +64,13 @@ public FabricDiscordSRV(DiscordSRVFabricBootstrap bootstrap) { this.commandHandler = new FabricCommandHandler(this); // Config - this.connectionConfigManager = new FabricConnectionConfigManager(this); - this.configManager = new FabricConfigManager(this); - this.messagesConfigManager = new FabricMessagesConfigManager(this); + this.connectionConfigManager = new ConnectionConfigManager<>(this, ConnectionConfig::new); + this.configManager = new ServerConfigManager<>(this, FabricConfig::new); + this.messagesConfigManager = new MessagesConfigManager<>(this, MessagesConfig::new); - registerEvents(); load(); + + registerEvents(); } private void registerEvents() { @@ -137,7 +136,7 @@ public ICommandHandler commandHandler() { } @Override - public ConnectionConfigManager connectionConfigManager() { + public ConnectionConfigManager connectionConfigManager() { return connectionConfigManager; } diff --git a/fabric/src/main/java/com/discordsrv/fabric/config/connection/FabricConnectionConfig.java b/fabric/src/main/java/com/discordsrv/fabric/config/connection/FabricConnectionConfig.java deleted file mode 100644 index 59c66cf8..00000000 --- a/fabric/src/main/java/com/discordsrv/fabric/config/connection/FabricConnectionConfig.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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 . - */ - -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 { - -} diff --git a/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricConfig.java b/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricConfig.java index 497af748..56e06771 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricConfig.java +++ b/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricConfig.java @@ -24,6 +24,7 @@ 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 com.discordsrv.common.config.main.linking.ServerRequiredLinkingConfig; import org.spongepowered.configurate.objectmapping.ConfigSerializable; @ConfigSerializable @@ -40,7 +41,7 @@ public BaseChannelConfig createDefaultChannel() { } @Order(5) - public FabricRequiredLinkingConfig requiredLinking = new FabricRequiredLinkingConfig(); + public ServerRequiredLinkingConfig requiredLinking = new ServerRequiredLinkingConfig(); @Override public PresenceUpdaterConfig defaultPresenceUpdater() { diff --git a/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricRequiredLinkingConfig.java b/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricRequiredLinkingConfig.java deleted file mode 100644 index 6267d502..00000000 --- a/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricRequiredLinkingConfig.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 . - */ - -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"; - - } -} diff --git a/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConfigManager.java b/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConfigManager.java deleted file mode 100644 index 417fdf33..00000000 --- a/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConfigManager.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 . - */ - -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 { - - public FabricConfigManager(DiscordSRV discordSRV) { - super(discordSRV); - } - - public FabricConfigManager(Path dataDirectory) { - super(dataDirectory); - } - - @Override - public FabricConfig createConfiguration() { - return new FabricConfig(); - } -} diff --git a/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConnectionConfigManager.java b/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConnectionConfigManager.java deleted file mode 100644 index 7ce7ae11..00000000 --- a/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricConnectionConfigManager.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 . - */ - -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 { - - public FabricConnectionConfigManager(DiscordSRV discordSRV) { - super(discordSRV); - } - - public FabricConnectionConfigManager(Path dataDirectory) { - super(dataDirectory); - } - - @Override - public FabricConnectionConfig createConfiguration() { - return new FabricConnectionConfig(); - } - -} diff --git a/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricMessagesConfigManager.java b/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricMessagesConfigManager.java deleted file mode 100644 index e80ab8df..00000000 --- a/fabric/src/main/java/com/discordsrv/fabric/config/manager/FabricMessagesConfigManager.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 . - */ - -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 { - - public FabricMessagesConfigManager(DiscordSRV discordSRV) { - super(discordSRV); - } - - @Override - public MessagesConfig createConfiguration() { - return new MessagesConfig(); - } -} diff --git a/fabric/src/main/java/com/discordsrv/fabric/listener/FabricChatListener.java b/fabric/src/main/java/com/discordsrv/fabric/listener/FabricChatListener.java index bacddcd6..c042d235 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/listener/FabricChatListener.java +++ b/fabric/src/main/java/com/discordsrv/fabric/listener/FabricChatListener.java @@ -1,3 +1,21 @@ +/* + * 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 . + */ + package com.discordsrv.fabric.listener; import com.discordsrv.api.component.MinecraftComponent; @@ -20,15 +38,15 @@ public FabricChatListener(FabricDiscordSRV discordSRV) { } 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 - )); +// 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 +// )); } } diff --git a/settings.gradle b/settings.gradle index d8190b87..c1dd0259 100644 --- a/settings.gradle +++ b/settings.gradle @@ -173,7 +173,6 @@ rootProject.name = 'DiscordSRV-Ascension' 'bukkit:compat:bukkit1_12', 'bukkit:compat:spigot', 'bukkit:compat:paper', 'bukkit:compat:folia', // Bungee 'bungee', 'bungee:loader', - // Velocity 'velocity', // Fabric From 2ec29d1d56886a57b9d5dc61fb2fd42732315dd5 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 13 Jan 2025 01:21:28 +0300 Subject: [PATCH 04/51] Fix H2 for fabric --- .../common/core/storage/impl/sql/file/H2Storage.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/com/discordsrv/common/core/storage/impl/sql/file/H2Storage.java b/common/src/main/java/com/discordsrv/common/core/storage/impl/sql/file/H2Storage.java index 03764652..38cd306b 100644 --- a/common/src/main/java/com/discordsrv/common/core/storage/impl/sql/file/H2Storage.java +++ b/common/src/main/java/com/discordsrv/common/core/storage/impl/sql/file/H2Storage.java @@ -22,6 +22,7 @@ import com.discordsrv.common.config.connection.StorageConfig; import com.discordsrv.common.core.storage.impl.sql.SQLStorage; import com.discordsrv.common.exception.StorageException; +import com.discordsrv.common.util.ReflectionUtil; import dev.vankka.dependencydownload.classloader.IsolatedClassLoader; import java.io.IOException; @@ -51,7 +52,13 @@ public void initialize() { StorageConfig storageConfig = discordSRV.connectionConfig().storage; try { - Class clazz = classLoader.loadClass("org.h2.jdbc.JdbcConnection"); + Class clazz; + if(ReflectionUtil.classExists("net.fabricmc.loader.api.FabricLoader")) { + clazz = getClass().getClassLoader().loadClass("org.h2.jdbc.JdbcConnection"); + } else { + clazz = classLoader.loadClass("org.h2.jdbc.JdbcConnection"); + } + Constructor constructor = clazz.getConstructor( String.class, // url Properties.class, // info From 91e2ed87e410d3e3ece31e8287a7b4734eb87e9d Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 13 Jan 2025 02:11:14 +0300 Subject: [PATCH 05/51] Oops. --- .../java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java | 1 - 1 file changed, 1 deletion(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java index cd614377..47aab2b9 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java +++ b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java @@ -67,7 +67,6 @@ public void onInitializeServer() { ServerLifecycleEvents.SERVER_STARTED.register(minecraftServer -> { this.minecraftServer = minecraftServer; lifecycleManager.loadAndEnable(() -> this.discordSRV = new FabricDiscordSRV(this)); - discordSRV.runEnable(); this.discordSRV.runServerStarted(); }); } From 325d029d767b6cacf16064f5621621e327bf1f73 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 13 Jan 2025 02:14:57 +0300 Subject: [PATCH 06/51] Working minecraft to discord chat --- .../discordsrv/fabric/FabricDiscordSRV.java | 19 +++++------- .../fabric/module/AbstractFabricModule.java | 25 +++++++++++++++ .../FabricChatModule.java} | 31 ++++++++++--------- 3 files changed, 49 insertions(+), 26 deletions(-) create mode 100644 fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java rename fabric/src/main/java/com/discordsrv/fabric/{listener/FabricChatListener.java => module/FabricChatModule.java} (68%) diff --git a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java index b4a412fe..8cc8c03a 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java +++ b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java @@ -28,7 +28,7 @@ import com.discordsrv.fabric.config.main.FabricConfig; import com.discordsrv.fabric.console.FabricConsole; import com.discordsrv.fabric.game.handler.FabricCommandHandler; -import com.discordsrv.fabric.listener.FabricChatListener; +import com.discordsrv.fabric.module.FabricChatModule; import com.discordsrv.fabric.player.FabricPlayerProvider; import com.discordsrv.fabric.plugin.FabricModManager; import com.discordsrv.common.AbstractDiscordSRV; @@ -69,15 +69,17 @@ public FabricDiscordSRV(DiscordSRVFabricBootstrap bootstrap) { this.messagesConfigManager = new MessagesConfigManager<>(this, MessagesConfig::new); load(); - - registerEvents(); } - private void registerEvents() { - new FabricChatListener(this); + @Override + protected void enable() throws Throwable { + super.enable(); + + // Chat registerModule(MinecraftToDiscordChatModule::new); - } + registerModule(FabricChatModule::new); + } //TODO: Implement this method. Maybe with KnotClassloader? @Override @@ -149,9 +151,4 @@ public MainConfigManager configManager() { public MessagesConfigManager messagesConfigManager() { return messagesConfigManager; } - - @Override - protected void enable() throws Throwable { - super.enable(); - } } diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java new file mode 100644 index 00000000..b7d326a1 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java @@ -0,0 +1,25 @@ +package com.discordsrv.fabric.module; + +import com.discordsrv.common.core.module.type.AbstractModule; +import com.discordsrv.fabric.FabricDiscordSRV; + +public abstract class AbstractFabricModule extends AbstractModule { + protected boolean enabled = false; + + public AbstractFabricModule(FabricDiscordSRV discordSRV) { + super(discordSRV); + } + + @Override + public void enable() { + enabled = true; + this.register(); + } + + @Override + public void disable() { + enabled = false; + } + + public void register() {} +} \ No newline at end of file diff --git a/fabric/src/main/java/com/discordsrv/fabric/listener/FabricChatListener.java b/fabric/src/main/java/com/discordsrv/fabric/module/FabricChatModule.java similarity index 68% rename from fabric/src/main/java/com/discordsrv/fabric/listener/FabricChatListener.java rename to fabric/src/main/java/com/discordsrv/fabric/module/FabricChatModule.java index c042d235..d6c5607e 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/listener/FabricChatListener.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/FabricChatModule.java @@ -16,37 +16,38 @@ * along with this program. If not, see . */ -package com.discordsrv.fabric.listener; +package com.discordsrv.fabric.module; -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.common.util.ComponentUtil; 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 { +public class FabricChatModule extends AbstractFabricModule { private final FabricDiscordSRV discordSRV; - public FabricChatListener(FabricDiscordSRV discordSRV) { + public FabricChatModule(FabricDiscordSRV discordSRV) { + super(discordSRV); this.discordSRV = discordSRV; + } + public void register() { 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 -// )); - } + if (!enabled) return; + discordSRV.eventBus().publish(new GameChatMessageReceiveEvent( + null, + discordSRV.playerProvider().player(serverPlayerEntity), + ComponentUtil.fromPlain(signedMessage.getSignedContent()), + new GlobalChannel(discordSRV), + false + )); + } } From 272052f53d6c5c8b7659bb802143eca6758091e1 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 13 Jan 2025 05:03:40 +0300 Subject: [PATCH 07/51] Working chat, join, quit and death messages --- .../discordsrv/fabric/FabricDiscordSRV.java | 8 +- .../fabric/module/AbstractFabricModule.java | 18 ++++ .../module/{ => chat}/FabricChatModule.java | 8 +- .../fabric/module/chat/FabricDeathModule.java | 71 ++++++++++++++++ .../fabric/module/chat/FabricJoinModule.java | 85 +++++++++++++++++++ .../fabric/module/chat/FabricQuitModule.java | 76 +++++++++++++++++ 6 files changed, 263 insertions(+), 3 deletions(-) rename fabric/src/main/java/com/discordsrv/fabric/module/{ => chat}/FabricChatModule.java (86%) create mode 100644 fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java diff --git a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java index 8cc8c03a..939823c6 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java +++ b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java @@ -28,7 +28,10 @@ import com.discordsrv.fabric.config.main.FabricConfig; import com.discordsrv.fabric.console.FabricConsole; import com.discordsrv.fabric.game.handler.FabricCommandHandler; -import com.discordsrv.fabric.module.FabricChatModule; +import com.discordsrv.fabric.module.chat.FabricChatModule; +import com.discordsrv.fabric.module.chat.FabricDeathModule; +import com.discordsrv.fabric.module.chat.FabricJoinModule; +import com.discordsrv.fabric.module.chat.FabricQuitModule; import com.discordsrv.fabric.player.FabricPlayerProvider; import com.discordsrv.fabric.plugin.FabricModManager; import com.discordsrv.common.AbstractDiscordSRV; @@ -78,6 +81,9 @@ protected void enable() throws Throwable { // Chat registerModule(MinecraftToDiscordChatModule::new); registerModule(FabricChatModule::new); + registerModule(FabricDeathModule::new); + registerModule(FabricJoinModule::new); + registerModule(FabricQuitModule::new); } diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java index b7d326a1..14b5525c 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java @@ -1,3 +1,21 @@ +/* + * 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 . + */ + package com.discordsrv.fabric.module; import com.discordsrv.common.core.module.type.AbstractModule; diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/FabricChatModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java similarity index 86% rename from fabric/src/main/java/com/discordsrv/fabric/module/FabricChatModule.java rename to fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java index d6c5607e..693d8dbb 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/FabricChatModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java @@ -16,17 +16,21 @@ * along with this program. If not, see . */ -package com.discordsrv.fabric.module; +package com.discordsrv.fabric.module.chat; import com.discordsrv.api.events.message.receive.game.GameChatMessageReceiveEvent; import com.discordsrv.common.feature.channel.global.GlobalChannel; import com.discordsrv.common.util.ComponentUtil; import com.discordsrv.fabric.FabricDiscordSRV; +import com.discordsrv.fabric.module.AbstractFabricModule; import net.fabricmc.fabric.api.message.v1.ServerMessageEvents; +import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; import net.minecraft.network.message.MessageType; import net.minecraft.network.message.SignedMessage; import net.minecraft.server.network.ServerPlayerEntity; +import java.util.Objects; + public class FabricChatModule extends AbstractFabricModule { private final FabricDiscordSRV discordSRV; @@ -45,7 +49,7 @@ private void onChatMessage(SignedMessage signedMessage, ServerPlayerEntity serve discordSRV.eventBus().publish(new GameChatMessageReceiveEvent( null, discordSRV.playerProvider().player(serverPlayerEntity), - ComponentUtil.fromPlain(signedMessage.getSignedContent()), + ComponentUtil.fromPlain(MinecraftServerAudiences.of(serverPlayerEntity.server).asAdventure(signedMessage).message()), new GlobalChannel(discordSRV), false )); diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java new file mode 100644 index 00000000..5f5429b2 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java @@ -0,0 +1,71 @@ +/* + * 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 . + */ + +package com.discordsrv.fabric.module.chat; + +import com.discordsrv.api.component.MinecraftComponent; +import com.discordsrv.api.events.message.receive.game.DeathMessageReceiveEvent; +import com.discordsrv.api.player.DiscordSRVPlayer; +import com.discordsrv.common.util.ComponentUtil; +import com.discordsrv.fabric.FabricDiscordSRV; +import com.discordsrv.fabric.module.AbstractFabricModule; +import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents; +import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.translation.GlobalTranslator; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import java.util.Locale; + + +public class FabricDeathModule extends AbstractFabricModule { + private final FabricDiscordSRV discordSRV; + + public FabricDeathModule(FabricDiscordSRV discordSRV) { + super(discordSRV); + this.discordSRV = discordSRV; + } + + public void register() { + ServerLivingEntityEvents.AFTER_DEATH.register(this::onDeath); + } + + private void onDeath(LivingEntity livingEntity, DamageSource damageSource) { + if (!enabled) return; + if(livingEntity instanceof ServerPlayerEntity) { + Text message = damageSource.getDeathMessage(livingEntity); + MinecraftComponent minecraftComponent = ComponentUtil.fromPlain(Formatting.strip(message.getString())); + + DiscordSRVPlayer player = discordSRV.playerProvider().player((ServerPlayerEntity) livingEntity); + discordSRV.eventBus().publish( + new DeathMessageReceiveEvent( + damageSource, + player, + minecraftComponent, + null, + false + ) + ); + } + } + +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java new file mode 100644 index 00000000..d15fe3d8 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java @@ -0,0 +1,85 @@ +/* + * 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 . + */ + +package com.discordsrv.fabric.module.chat; + +import com.discordsrv.api.component.MinecraftComponent; +import com.discordsrv.api.events.message.receive.game.JoinMessageReceiveEvent; +import com.discordsrv.api.player.DiscordSRVPlayer; +import com.discordsrv.common.util.ComponentUtil; +import com.discordsrv.fabric.FabricDiscordSRV; +import com.discordsrv.fabric.module.AbstractFabricModule; +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.translation.GlobalTranslator; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import java.util.Locale; +import java.util.Objects; + +public class FabricJoinModule extends AbstractFabricModule { + private final FabricDiscordSRV discordSRV; + + public FabricJoinModule(FabricDiscordSRV discordSRV) { + super(discordSRV); + this.discordSRV = discordSRV; + } + + public void register() { + ServerPlayConnectionEvents.JOIN.register(this::onJoin); + + } + + private void onJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSender packetSender, MinecraftServer minecraftServer) { + if (!enabled) return; + + ServerPlayerEntity playerEntity = serverPlayNetworkHandler.player; + MinecraftComponent component = getJoinMessage(playerEntity); + boolean firstJoin = !Objects.requireNonNull(minecraftServer.getUserCache()).findByName(serverPlayNetworkHandler.player.getGameProfile().getName()).isPresent(); + + DiscordSRVPlayer player = discordSRV.playerProvider().player(playerEntity); + discordSRV.eventBus().publish( + new JoinMessageReceiveEvent( + serverPlayNetworkHandler, + player, + component, + null, + firstJoin, + false + ) + ); + } + + private MinecraftComponent getJoinMessage(ServerPlayerEntity playerEntity) { + MutableText mutableText; + if (playerEntity.getGameProfile().getName().equalsIgnoreCase(playerEntity.getName().getString())) { + mutableText = Text.translatable("multiplayer.player.joined", playerEntity.getDisplayName()); + } else { + mutableText = Text.translatable("multiplayer.player.joined.renamed", playerEntity.getDisplayName(), playerEntity.getName()); + } + + return ComponentUtil.fromPlain(Formatting.strip(mutableText.formatted(Formatting.YELLOW).getString())); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java new file mode 100644 index 00000000..df3e75c6 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java @@ -0,0 +1,76 @@ +/* + * 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 . + */ + +package com.discordsrv.fabric.module.chat; + +import com.discordsrv.api.component.MinecraftComponent; +import com.discordsrv.api.events.message.receive.game.LeaveMessageReceiveEvent; +import com.discordsrv.api.player.DiscordSRVPlayer; +import com.discordsrv.common.util.ComponentUtil; +import com.discordsrv.fabric.FabricDiscordSRV; +import com.discordsrv.fabric.module.AbstractFabricModule; +import com.discordsrv.fabric.player.FabricPlayer; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.translation.GlobalTranslator; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.Identifier; + +import java.util.Locale; + +public class FabricQuitModule extends AbstractFabricModule { + private final FabricDiscordSRV discordSRV; + + public FabricQuitModule(FabricDiscordSRV discordSRV) { + super(discordSRV); + this.discordSRV = discordSRV; + } + + public void register() { + // First phase + ServerPlayConnectionEvents.DISCONNECT.register(this::onDisconnect); + } + + private void onDisconnect(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) { + if (!enabled) return; + + ServerPlayerEntity player = serverPlayNetworkHandler.player; + MinecraftComponent component = getQuitMessage(player); + + discordSRV.eventBus().publish( + new LeaveMessageReceiveEvent( + serverPlayNetworkHandler, + new FabricPlayer(discordSRV, player), + component, + null, + component == null + ) + ); + } + + public MinecraftComponent getQuitMessage(ServerPlayerEntity player) { + Text message = Text.translatable("multiplayer.player.left", player.getDisplayName()).formatted(Formatting.YELLOW); + + return ComponentUtil.fromPlain(Formatting.strip(message.getString())); + } +} From f98a4afdb92809e6ef5a4e74da5ec2a3d5658e18 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 13 Jan 2025 06:24:36 +0300 Subject: [PATCH 08/51] Send server is stopping --- .../java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java index 47aab2b9..098acc8e 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java +++ b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java @@ -69,6 +69,10 @@ public void onInitializeServer() { lifecycleManager.loadAndEnable(() -> this.discordSRV = new FabricDiscordSRV(this)); this.discordSRV.runServerStarted(); }); + + ServerLifecycleEvents.SERVER_STOPPING.register(minecraftServer -> { + this.discordSRV.runDisable(); + }); } @Override From 4c198909f3c7ab533a1e919637d9b9eda07f03ca Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 13 Jan 2025 06:24:59 +0300 Subject: [PATCH 09/51] Add advancement --- .../discordsrv/fabric/FabricDiscordSRV.java | 6 +- .../mixin/PlayerAdvancementTrackerMixin.java | 22 +++++++ .../module/chat/FabricAdvancementModule.java | 63 +++++++++++++++++++ .../src/main/resources/discordsrv.mixins.json | 11 ++++ fabric/src/main/resources/fabric.mod.json | 4 +- 5 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java create mode 100644 fabric/src/main/resources/discordsrv.mixins.json diff --git a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java index 939823c6..cfecd47d 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java +++ b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java @@ -28,10 +28,7 @@ import com.discordsrv.fabric.config.main.FabricConfig; import com.discordsrv.fabric.console.FabricConsole; import com.discordsrv.fabric.game.handler.FabricCommandHandler; -import com.discordsrv.fabric.module.chat.FabricChatModule; -import com.discordsrv.fabric.module.chat.FabricDeathModule; -import com.discordsrv.fabric.module.chat.FabricJoinModule; -import com.discordsrv.fabric.module.chat.FabricQuitModule; +import com.discordsrv.fabric.module.chat.*; import com.discordsrv.fabric.player.FabricPlayerProvider; import com.discordsrv.fabric.plugin.FabricModManager; import com.discordsrv.common.AbstractDiscordSRV; @@ -84,6 +81,7 @@ protected void enable() throws Throwable { registerModule(FabricDeathModule::new); registerModule(FabricJoinModule::new); registerModule(FabricQuitModule::new); + registerModule(FabricAdvancementModule::new); } diff --git a/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java b/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java new file mode 100644 index 00000000..0ba4ec1c --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java @@ -0,0 +1,22 @@ +package com.discordsrv.fabric.mixin; + +import com.discordsrv.fabric.module.chat.FabricAdvancementModule; +import net.minecraft.advancement.AdvancementEntry; +import net.minecraft.advancement.PlayerAdvancementTracker; +import net.minecraft.server.network.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(PlayerAdvancementTracker.class) +public class PlayerAdvancementTrackerMixin { + @Shadow + ServerPlayerEntity owner; + + @Inject(method = "grantCriterion", at = @At(value = "INVOKE", target = "Lnet/minecraft/advancement/PlayerAdvancementTracker;onStatusUpdate(Lnet/minecraft/advancement/AdvancementEntry;)V")) + public void onGrant(AdvancementEntry advancementEntry, String criterionName, CallbackInfoReturnable cir) { + FabricAdvancementModule.onGrant(advancementEntry, criterionName, cir, owner); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java new file mode 100644 index 00000000..c889a148 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java @@ -0,0 +1,63 @@ +/* + * 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 . + */ + +package com.discordsrv.fabric.module.chat; + +import com.discordsrv.api.component.MinecraftComponent; +import com.discordsrv.api.events.message.receive.game.AwardMessageReceiveEvent; +import com.discordsrv.common.abstraction.player.IPlayer; +import com.discordsrv.common.util.ComponentUtil; +import com.discordsrv.fabric.FabricDiscordSRV; +import com.discordsrv.fabric.module.AbstractFabricModule; +import net.kyori.adventure.text.Component; +import net.minecraft.advancement.AdvancementEntry; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Formatting; +import org.apache.commons.lang3.text.WordUtils; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +public class FabricAdvancementModule extends AbstractFabricModule { + private final FabricDiscordSRV discordSRV; + private static FabricAdvancementModule instance; + + public FabricAdvancementModule(FabricDiscordSRV discordSRV) { + super(discordSRV); + this.discordSRV = discordSRV; + instance = this; + } + + public static void onGrant(AdvancementEntry advancementEntry, String criterionName, CallbackInfoReturnable cir, ServerPlayerEntity owner) { + if (instance == null || !instance.enabled) return; + + FabricDiscordSRV discordSRV = instance.discordSRV; + String achievement = Formatting.strip(advancementEntry.value().name().get().getString()); + MinecraftComponent achievementName = ComponentUtil.fromPlain(achievement); + + IPlayer player = discordSRV.playerProvider().player(owner); + discordSRV.eventBus().publish( + new AwardMessageReceiveEvent( + null, + player, + achievementName, + null, + null, + false + ) + ); + } +} diff --git a/fabric/src/main/resources/discordsrv.mixins.json b/fabric/src/main/resources/discordsrv.mixins.json new file mode 100644 index 00000000..62f11d08 --- /dev/null +++ b/fabric/src/main/resources/discordsrv.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "package": "com.discordsrv.fabric.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "PlayerAdvancementTrackerMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index a490e04d..f2e0fe74 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -13,7 +13,9 @@ "com.discordsrv.fabric.DiscordSRVFabricBootstrap" ] }, - "mixins": [], + "mixins": [ + "discordsrv.mixins.json" + ], "jars": [ { "file": "META-INF/jars/adventure-platform-mod-shared-fabric-repack-6.1.0.jar" From 46cef7c52e61e5afcf8cbb1462f87ef9a406a8f1 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 13 Jan 2025 07:01:33 +0300 Subject: [PATCH 10/51] Add required linking (Only kick implemented) --- .../discordsrv/fabric/FabricDiscordSRV.java | 3 + .../fabric/module/chat/FabricJoinModule.java | 8 + .../FabricRequiredLinkingModule.java | 292 ++++++++++++++++++ 3 files changed, 303 insertions(+) create mode 100644 fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java diff --git a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java index cfecd47d..15dcbbf3 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java +++ b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java @@ -29,6 +29,7 @@ import com.discordsrv.fabric.console.FabricConsole; import com.discordsrv.fabric.game.handler.FabricCommandHandler; import com.discordsrv.fabric.module.chat.*; +import com.discordsrv.fabric.requiredlinking.FabricRequiredLinkingModule; import com.discordsrv.fabric.player.FabricPlayerProvider; import com.discordsrv.fabric.plugin.FabricModManager; import com.discordsrv.common.AbstractDiscordSRV; @@ -83,6 +84,8 @@ protected void enable() throws Throwable { registerModule(FabricQuitModule::new); registerModule(FabricAdvancementModule::new); + // Required linking + registerModule(FabricRequiredLinkingModule::new); } //TODO: Implement this method. Maybe with KnotClassloader? diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java index d15fe3d8..209e4895 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java @@ -21,9 +21,11 @@ import com.discordsrv.api.component.MinecraftComponent; import com.discordsrv.api.events.message.receive.game.JoinMessageReceiveEvent; import com.discordsrv.api.player.DiscordSRVPlayer; +import com.discordsrv.common.feature.bansync.BanSyncModule; import com.discordsrv.common.util.ComponentUtil; import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.fabric.module.AbstractFabricModule; +import com.discordsrv.fabric.requiredlinking.FabricRequiredLinkingModule; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; @@ -55,6 +57,12 @@ public void register() { private void onJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSender packetSender, MinecraftServer minecraftServer) { if (!enabled) return; + FabricRequiredLinkingModule module = discordSRV.getModule(FabricRequiredLinkingModule.class); + if(module != null && !module.isLoginCancelled(serverPlayNetworkHandler.player.getUuid())) { + module.removeLoginCancelled(serverPlayNetworkHandler.player.getUuid()); + return; + } + ServerPlayerEntity playerEntity = serverPlayNetworkHandler.player; MinecraftComponent component = getJoinMessage(playerEntity); boolean firstJoin = !Objects.requireNonNull(minecraftServer.getUserCache()).findByName(serverPlayNetworkHandler.player.getGameProfile().getName()).isPresent(); diff --git a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java new file mode 100644 index 00000000..ca0b0d6a --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java @@ -0,0 +1,292 @@ +/* + * 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 . + */ + +package com.discordsrv.fabric.requiredlinking; + +import com.discordsrv.fabric.FabricDiscordSRV; +import com.discordsrv.common.DiscordSRV; +import com.discordsrv.common.abstraction.player.IPlayer; +import com.discordsrv.common.config.main.linking.ServerRequiredLinkingConfig; +import com.discordsrv.common.feature.linking.LinkStore; +import com.discordsrv.common.feature.linking.requirelinking.ServerRequireLinkingModule; +import com.github.benmanes.caffeine.cache.Cache; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; +import net.kyori.adventure.text.Component; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + + +public class FabricRequiredLinkingModule extends ServerRequireLinkingModule { + + private boolean enabled = false; + private final Cache linkCheckRateLimit; + + public FabricRequiredLinkingModule(FabricDiscordSRV discordSRV) { + super(discordSRV); + this.linkCheckRateLimit = discordSRV.caffeineBuilder() + .expireAfterWrite(LinkStore.LINKING_CODE_RATE_LIMIT) + .build(); + + register(); + } + + @Override + public ServerRequiredLinkingConfig config() { + return discordSRV.config().requiredLinking; + } + + @Override + public void enable() { + super.enable(); + + this.enabled = true; + } + + public void register() { + ServerPlayConnectionEvents.INIT.register(this::onPlayerPreLogin); + + } + + @Override + public void disable() { + super.disable(); + + this.enabled = false; + } + + private final List loginsCancelled = new CopyOnWriteArrayList<>(); + + public boolean isLoginCancelled(UUID playerUUID) { + return loginsCancelled.contains(playerUUID); + } + + public void removeLoginCancelled(UUID playerUUID) { + loginsCancelled.remove(playerUUID); + } + + private void onPlayerPreLogin(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) { + if(!this.enabled) return; + + ServerRequiredLinkingConfig config = config(); + if (!config.enabled || config.action != ServerRequiredLinkingConfig.Action.KICK) { + return; + } + + ServerPlayerEntity player = serverPlayNetworkHandler.player; + UUID playerUUID = player.getUuid(); + String playerName = player.getName().getString(); + + Component kickReason = getBlockReason(playerUUID, playerName, true).join(); + if (kickReason != null) { + serverPlayNetworkHandler.disconnect(MinecraftServerAudiences.of(minecraftServer).asNative(kickReason)); + loginsCancelled.add(playerUUID); + } + } + + @Override + public void recheck(IPlayer player) { + getBlockReason(player.uniqueId(), player.username(), false).whenComplete((component, throwable) -> { + if (component != null) { + switch (action()) { + case KICK: + player.kick(component); + break; + case FREEZE: + freeze(player, component); + break; + } + } else if (action() == ServerRequiredLinkingConfig.Action.FREEZE) { + frozen.remove(player.uniqueId()); + } + }); + } + + public ServerRequiredLinkingConfig.Action action() { + return config().action; + } + + // + // Freeze - Not implemented yet + // + + private final Map frozen = new ConcurrentHashMap<>(); + private final List loginsHandled = new CopyOnWriteArrayList<>(); + + private boolean isFrozen(ServerPlayerEntity player) { + return frozen.containsKey(player.getUuid()); + } + + private void freeze(IPlayer player, Component blockReason) { + frozen.put(player.uniqueId(), blockReason); + player.sendMessage(blockReason); + } + +// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) +// public void onAsyncPlayerPreLogin(AsyncPlayerPreLoginEvent event) { +// if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) { +// return; +// } +// +// UUID playerUUID = event.getUniqueId(); +// loginsHandled.add(playerUUID); +// handleLogin(playerUUID, event.getName()); +// } +// +// @EventHandler(priority = EventPriority.MONITOR) +// public void onPlayerLogin(PlayerLoginEvent event) { +// if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) { +// frozen.remove(event.getPlayer().getUniqueId()); +// } +// } +// +// @EventHandler(priority = EventPriority.LOWEST) +// public void onPlayerJoinLowest(PlayerJoinEvent event) { +// Player player = event.getPlayer(); +// UUID playerUUID = player.getUniqueId(); +// if (!loginsHandled.remove(playerUUID)) { +// handleLogin(playerUUID, player.getName()); +// } +// } +// +// @EventHandler(priority = EventPriority.MONITOR) +// public void onPlayerJoinMonitor(PlayerJoinEvent event) { +// UUID playerUUID = event.getPlayer().getUniqueId(); +// +// Component blockReason = frozen.get(playerUUID); +// if (blockReason == null) { +// return; +// } +// +// IPlayer srvPlayer = discordSRV.playerProvider().player(playerUUID); +// if (srvPlayer == null) { +// throw new IllegalStateException("Player not available: " + playerUUID); +// } +// +// srvPlayer.sendMessage(blockReason); +// } + + private void handleLogin(UUID playerUUID, String username) { + if (discordSRV.isShutdown()) { + return; + } else if (!discordSRV.isReady()) { + try { + discordSRV.waitForStatus(DiscordSRV.Status.CONNECTED); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + ServerRequiredLinkingConfig config = config(); + if (!config.enabled || config.action != ServerRequiredLinkingConfig.Action.FREEZE) { + return; + } + + Component blockReason = getBlockReason(playerUUID, username, false).join(); + if (blockReason != null) { + frozen.put(playerUUID, blockReason); + } + } + +// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) +// public void onPlayerMove(PlayerMoveEvent event) { +// Component freezeReason = frozen.get(event.getPlayer().getUniqueId()); +// if (freezeReason == null) { +// return; +// } +// +// Location from = event.getFrom(), to = event.getTo(); +// if (from.getWorld().getName().equals(to.getWorld().getName()) +// && from.getBlockX() == to.getBlockX() +// && from.getBlockZ() == to.getBlockZ() +// && from.getBlockY() >= to.getBlockY()) { +// return; +// } +// +// event.setTo( +// new Location( +// from.getWorld(), +// from.getBlockX() + 0.5, +// from.getBlockY(), +// from.getBlockZ() + 0.5, +// from.getYaw(), +// from.getPitch() +// ) +// ); +// +// IPlayer player = discordSRV.playerProvider().player(event.getPlayer()); +// player.sendMessage(freezeReason); +// } +// +// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) +// public void onAsyncPlayerChat(AsyncPlayerChatEvent event) { +// Component freezeReason = frozen.get(event.getPlayer().getUniqueId()); +// if (freezeReason == null) { +// event.getRecipients().removeIf(this::isFrozen); +// return; +// } +// +// event.setCancelled(true); +// +// IPlayer player = discordSRV.playerProvider().player(event.getPlayer()); +// player.sendMessage(freezeReason); +// } +// +// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) +// public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { +// if (!isFrozen(event.getPlayer())) { +// return; +// } +// +// event.setCancelled(true); +// +// String message = event.getMessage(); +// if (message.startsWith("/")) message = message.substring(1); +// if (message.equals("discord link") || message.equals("link")) { +// IPlayer player = discordSRV.playerProvider().player(event.getPlayer()); +// +// if (linkCheckRateLimit.getIfPresent(player.uniqueId()) != null) { +// player.sendMessage(discordSRV.messagesConfig(player).pleaseWaitBeforeRunningThatCommandAgain.asComponent()); +// return; +// } +// linkCheckRateLimit.put(player.uniqueId(), true); +// +// player.sendMessage(Component.text("Checking...")); +// +// UUID uuid = player.uniqueId(); +// getBlockReason(uuid, player.username(), false).whenComplete((reason, t) -> { +// if (t != null) { +// return; +// } +// +// if (reason == null) { +// frozen.remove(uuid); +// } else { +// freeze(player, reason); +// } +// }); +// } +// } +} From 4da8b012ef375bb16b4722156b606985d9d9799f Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 13 Jan 2025 08:19:19 +0300 Subject: [PATCH 11/51] Add ban syncing --- .../discordsrv/fabric/FabricDiscordSRV.java | 4 + .../fabric/mixin/ban/BanCommandMixin.java | 19 +++ .../fabric/module/ban/FabricBanModule.java | 115 ++++++++++++++++++ .../src/main/resources/discordsrv.mixins.json | 3 +- 4 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 fabric/src/main/java/com/discordsrv/fabric/mixin/ban/BanCommandMixin.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java diff --git a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java index 15dcbbf3..2496577c 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java +++ b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java @@ -29,6 +29,7 @@ import com.discordsrv.fabric.console.FabricConsole; import com.discordsrv.fabric.game.handler.FabricCommandHandler; import com.discordsrv.fabric.module.chat.*; +import com.discordsrv.fabric.module.ban.FabricBanModule; import com.discordsrv.fabric.requiredlinking.FabricRequiredLinkingModule; import com.discordsrv.fabric.player.FabricPlayerProvider; import com.discordsrv.fabric.plugin.FabricModManager; @@ -86,6 +87,9 @@ protected void enable() throws Throwable { // Required linking registerModule(FabricRequiredLinkingModule::new); + + // Punishments + registerModule(FabricBanModule::new); } //TODO: Implement this method. Maybe with KnotClassloader? diff --git a/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/BanCommandMixin.java b/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/BanCommandMixin.java new file mode 100644 index 00000000..e09099b6 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/BanCommandMixin.java @@ -0,0 +1,19 @@ +package com.discordsrv.fabric.mixin.ban; + +import com.discordsrv.fabric.module.ban.FabricBanModule; +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.dedicated.command.BanCommand; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(BanCommand.class) +public class BanCommandMixin { + + @Inject(method = "ban", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/BannedPlayerEntry;(Lcom/mojang/authlib/GameProfile;Ljava/util/Date;Ljava/lang/String;Ljava/util/Date;Ljava/lang/String;)V")) + private static void ban(CallbackInfoReturnable cir, @Local GameProfile gameProfile) { + FabricBanModule.onBan(gameProfile); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java new file mode 100644 index 00000000..9a7c03fa --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java @@ -0,0 +1,115 @@ +package com.discordsrv.fabric.module.ban; + +import com.discordsrv.api.component.MinecraftComponent; +import com.discordsrv.api.module.type.PunishmentModule; +import com.discordsrv.api.punishment.Punishment; +import com.discordsrv.common.feature.bansync.BanSyncModule; +import com.discordsrv.common.util.ComponentUtil; +import com.discordsrv.fabric.FabricDiscordSRV; +import com.discordsrv.fabric.module.AbstractFabricModule; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.BannedPlayerEntry; +import net.minecraft.server.BannedPlayerList; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.time.Instant; +import java.util.Date; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +public class FabricBanModule extends AbstractFabricModule implements PunishmentModule.Bans { + private static FabricBanModule instance; + + public FabricBanModule(FabricDiscordSRV discordSRV) { + super(discordSRV); + + instance = this; + } + + + @Override + public void enable() { + this.enabled = true; + } + + public static void onBan(GameProfile gameProfile) { + FabricDiscordSRV discordSRV = instance.discordSRV; + BanSyncModule module = discordSRV.getModule(BanSyncModule.class); + if (module != null) { + instance.getBan(gameProfile.getId()) + .whenComplete((punishment, t) -> module.notifyBanned(Objects.requireNonNull(discordSRV.playerProvider().player(gameProfile.getId())), punishment)); + } + } + + @Override + public CompletableFuture<@Nullable Punishment> getBan(@NotNull UUID playerUUID) { + BannedPlayerList banList = discordSRV.getServer().getPlayerManager().getUserBanList(); + + Optional gameProfile = Objects.requireNonNull(discordSRV.getServer().getUserCache()).getByUuid(playerUUID); + if (!gameProfile.isPresent()) { + return CompletableFuture.completedFuture(null); + } + + BannedPlayerEntry banEntry = banList.get(gameProfile.get()); + if (banEntry == null) { + return CompletableFuture.completedFuture(null); + } + Date expiration = banEntry.getExpiryDate(); + + return CompletableFuture.completedFuture(new Punishment( + expiration != null ? expiration.toInstant() : null, + ComponentUtil.fromPlain(banEntry.getReason()), + ComponentUtil.fromPlain(banEntry.getSource()) + )); + } + + @Override + public CompletableFuture addBan( + @NotNull UUID playerUUID, + @Nullable Instant until, + @Nullable MinecraftComponent reason, + @NotNull MinecraftComponent punisher + ) { + try { + String reasonLegacy = reason != null ? ComponentUtil.fromAPI(reason).toString() : null; + String punisherLegacy = ComponentUtil.fromAPI(punisher).toString(); + + BannedPlayerList banList = discordSRV.getServer().getPlayerManager().getUserBanList(); + + discordSRV.getServer().getPlayerManager().getUserBanList().add(new BannedPlayerEntry( + discordSRV.getServer().getUserCache().getByUuid(playerUUID).get(), + null, + ComponentUtil.fromAPI(reason).toString(), + null, + ComponentUtil.fromAPI(punisher).toString() + )); + + ServerPlayerEntity serverPlayerEntity = discordSRV.getServer().getPlayerManager().getPlayer(playerUUID); + if (serverPlayerEntity != null) { + serverPlayerEntity.networkHandler.disconnect(Text.translatable("multiplayer.disconnect.banned")); + } + } catch (Exception e) { + discordSRV.logger().error("Failed to ban player", e); + } + + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletableFuture removeBan(@NotNull UUID playerUUID) { + BannedPlayerList banList = discordSRV.getServer().getPlayerManager().getUserBanList(); + + Optional gameProfile = Objects.requireNonNull(discordSRV.getServer().getUserCache()).getByUuid(playerUUID); + if (!gameProfile.isPresent()) { + return CompletableFuture.completedFuture(null); + } + + banList.remove(gameProfile.get()); + return CompletableFuture.completedFuture(null); + } +} diff --git a/fabric/src/main/resources/discordsrv.mixins.json b/fabric/src/main/resources/discordsrv.mixins.json index 62f11d08..da069047 100644 --- a/fabric/src/main/resources/discordsrv.mixins.json +++ b/fabric/src/main/resources/discordsrv.mixins.json @@ -3,7 +3,8 @@ "package": "com.discordsrv.fabric.mixin", "compatibilityLevel": "JAVA_21", "mixins": [ - "PlayerAdvancementTrackerMixin" + "PlayerAdvancementTrackerMixin", + "ban.BanCommandMixin" ], "injectors": { "defaultRequire": 1 From ae195cf9f9f4a06adc942d8ec44fbafb556f7d41 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 13 Jan 2025 08:20:08 +0300 Subject: [PATCH 12/51] Remove unused imports causing warnings --- .../discordsrv/fabric/module/chat/FabricAdvancementModule.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java index c889a148..44e90c0b 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java @@ -24,11 +24,9 @@ import com.discordsrv.common.util.ComponentUtil; import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.fabric.module.AbstractFabricModule; -import net.kyori.adventure.text.Component; import net.minecraft.advancement.AdvancementEntry; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Formatting; -import org.apache.commons.lang3.text.WordUtils; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; public class FabricAdvancementModule extends AbstractFabricModule { From b461e10608cac3fb6bf2b250619fb659ea4a872d Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 13 Jan 2025 08:41:17 +0300 Subject: [PATCH 13/51] Fix ban check being too early --- .../java/com/discordsrv/fabric/mixin/ban/BanCommandMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/BanCommandMixin.java b/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/BanCommandMixin.java index e09099b6..5ee4fd2e 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/BanCommandMixin.java +++ b/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/BanCommandMixin.java @@ -12,7 +12,7 @@ @Mixin(BanCommand.class) public class BanCommandMixin { - @Inject(method = "ban", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/BannedPlayerEntry;(Lcom/mojang/authlib/GameProfile;Ljava/util/Date;Ljava/lang/String;Ljava/util/Date;Ljava/lang/String;)V")) + @Inject(method = "ban", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/BannedPlayerList;add(Lnet/minecraft/server/ServerConfigEntry;)V", shift = At.Shift.AFTER)) private static void ban(CallbackInfoReturnable cir, @Local GameProfile gameProfile) { FabricBanModule.onBan(gameProfile); } From f3337060e4b2eeefab2a732e63eb9a4e34988f01 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 13 Jan 2025 08:45:33 +0300 Subject: [PATCH 14/51] Add TODO tasks. --- .../fabric/requiredlinking/FabricRequiredLinkingModule.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java index ca0b0d6a..2f0b7060 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java @@ -66,8 +66,8 @@ public void enable() { } public void register() { + // TODO: mixin into net.minecraft.server.PlayerManager#checkCanJoin ServerPlayConnectionEvents.INIT.register(this::onPlayerPreLogin); - } @Override @@ -129,7 +129,7 @@ public ServerRequiredLinkingConfig.Action action() { } // - // Freeze - Not implemented yet + // Freeze - TODO: Not implemented yet // private final Map frozen = new ConcurrentHashMap<>(); From ea22f19d24a95630169d588a4e6ae6a3401eec10 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 13 Jan 2025 08:54:38 +0300 Subject: [PATCH 15/51] Some more stuff --- .../mixin/PlayerAdvancementTrackerMixin.java | 20 ++++++++++++++++++- .../fabric/mixin/ban/BanCommandMixin.java | 18 +++++++++++++++++ .../fabric/module/ban/FabricBanModule.java | 18 +++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java b/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java index 0ba4ec1c..d04f830b 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java +++ b/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java @@ -1,3 +1,21 @@ +/* + * 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 . + */ + package com.discordsrv.fabric.mixin; import com.discordsrv.fabric.module.chat.FabricAdvancementModule; @@ -13,7 +31,7 @@ @Mixin(PlayerAdvancementTracker.class) public class PlayerAdvancementTrackerMixin { @Shadow - ServerPlayerEntity owner; + private ServerPlayerEntity owner; @Inject(method = "grantCriterion", at = @At(value = "INVOKE", target = "Lnet/minecraft/advancement/PlayerAdvancementTracker;onStatusUpdate(Lnet/minecraft/advancement/AdvancementEntry;)V")) public void onGrant(AdvancementEntry advancementEntry, String criterionName, CallbackInfoReturnable cir) { diff --git a/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/BanCommandMixin.java b/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/BanCommandMixin.java index 5ee4fd2e..2e486dc5 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/BanCommandMixin.java +++ b/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/BanCommandMixin.java @@ -1,3 +1,21 @@ +/* + * 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 . + */ + package com.discordsrv.fabric.mixin.ban; import com.discordsrv.fabric.module.ban.FabricBanModule; diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java index 9a7c03fa..aadbb1c6 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java @@ -1,3 +1,21 @@ +/* + * 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 . + */ + package com.discordsrv.fabric.module.ban; import com.discordsrv.api.component.MinecraftComponent; From 836867eb36ce0755aaa284ad191c3fd1b9a8aefc Mon Sep 17 00:00:00 2001 From: Vankka Date: Mon, 13 Jan 2025 20:03:05 +0200 Subject: [PATCH 16/51] Fix Fabric build --- buildscript/relocations.gradle | 8 ---- .../core/storage/impl/sql/file/H2Storage.java | 8 +--- fabric/build.gradle | 47 +++++++++---------- settings.gradle | 4 +- 4 files changed, 24 insertions(+), 43 deletions(-) diff --git a/buildscript/relocations.gradle b/buildscript/relocations.gradle index 99de544b..4fa722b1 100644 --- a/buildscript/relocations.gradle +++ b/buildscript/relocations.gradle @@ -70,14 +70,6 @@ '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 diff --git a/common/src/main/java/com/discordsrv/common/core/storage/impl/sql/file/H2Storage.java b/common/src/main/java/com/discordsrv/common/core/storage/impl/sql/file/H2Storage.java index 38cd306b..19414773 100644 --- a/common/src/main/java/com/discordsrv/common/core/storage/impl/sql/file/H2Storage.java +++ b/common/src/main/java/com/discordsrv/common/core/storage/impl/sql/file/H2Storage.java @@ -22,7 +22,6 @@ import com.discordsrv.common.config.connection.StorageConfig; import com.discordsrv.common.core.storage.impl.sql.SQLStorage; import com.discordsrv.common.exception.StorageException; -import com.discordsrv.common.util.ReflectionUtil; import dev.vankka.dependencydownload.classloader.IsolatedClassLoader; import java.io.IOException; @@ -52,12 +51,7 @@ public void initialize() { StorageConfig storageConfig = discordSRV.connectionConfig().storage; try { - Class clazz; - if(ReflectionUtil.classExists("net.fabricmc.loader.api.FabricLoader")) { - clazz = getClass().getClassLoader().loadClass("org.h2.jdbc.JdbcConnection"); - } else { - clazz = classLoader.loadClass("org.h2.jdbc.JdbcConnection"); - } + Class clazz = classLoader.loadClass("org.h2.jdbc.JdbcConnection"); Constructor constructor = clazz.getConstructor( String.class, // url diff --git a/fabric/build.gradle b/fabric/build.gradle index ad4d1755..f7ccbd59 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -15,13 +15,22 @@ processResources { filesMatching('**/fabric.mod.json') { expand 'VERSION': project.version, 'MINECRAFT_VERSION': libs.fabric.minecraft.get().version, 'LOADER_VERSION': libs.fabric.loader.get().version } + dependsOn generateRuntimeDownloadResourceForRuntimeDownloadOnly } shadowJar { - archiveBaseName = 'DiscordSRV-Fabric' + configurations = [project.configurations.shadow] mergeServiceFiles() } +remapJar { + dependsOn shadowJar + mustRunAfter shadowJar + inputFile = shadowJar.archiveFile + archiveBaseName = 'DiscordSRV-Fabric' + archiveClassifier = jar.archiveClassifier +} + loom { serverOnlyMinecraftJar() } @@ -29,7 +38,7 @@ loom { repositories { exclusiveContent { forRepository { - maven { url 'https://maven.fabricmc.net/' } + maven { url = 'https://maven.fabricmc.net/' } } filter { includeGroup 'net.fabricmc' @@ -42,39 +51,25 @@ dependencies { minecraft(libs.fabric.minecraft) mappings(variantOf(libs.fabric.yarn) { classifier("v2") }) compileOnly(libs.fabric.loader) + + // Fabric API modImplementation(libs.fabric.api) + modImplementation(libs.fabric.permissions.api) + include(libs.fabric.permissions.api) // API annotationProcessor project(':api') - implementation project(':common:common-api') + shadow project(':common:common-api') // Common - implementation project(':common') + shadow project(':common') // Adventure modImplementation(libs.adventure.platform.fabric) + include(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")} + shadow(libs.mcdependencydownload.fabric) { + exclude module: 'fabric-loader' + } } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index c1dd0259..f1772537 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,8 +1,8 @@ pluginManagement { repositories { mavenLocal() - maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' } - maven { url 'https://maven.fabricmc.net/'} + maven { url = 'https://s01.oss.sonatype.org/content/repositories/snapshots/' } + maven { url = 'https://maven.fabricmc.net/'} gradlePluginPortal() } } From db8d216c1d17b103855a19b9ffc518177a7aa95a Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Tue, 14 Jan 2025 04:56:59 +0300 Subject: [PATCH 17/51] Target java 21 --- fabric/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fabric/build.gradle b/fabric/build.gradle index f7ccbd59..894d4d34 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -8,7 +8,8 @@ configurations.all { } java { - disableAutoTargetJvm() // Requires Java 21, we target 8 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } processResources { From 2e12f80c9aeefdd90fac0cc215e63409a57c91c7 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Tue, 14 Jan 2025 04:57:41 +0300 Subject: [PATCH 18/51] Don't hang the server if the mod crashed before initialization --- .../java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java index 098acc8e..6e487941 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java +++ b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java @@ -71,7 +71,7 @@ public void onInitializeServer() { }); ServerLifecycleEvents.SERVER_STOPPING.register(minecraftServer -> { - this.discordSRV.runDisable(); + if(this.discordSRV != null) this.discordSRV.runDisable(); }); } From 70da6026afcabb179503f117d3f4d1d5ab438de0 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Tue, 14 Jan 2025 04:58:00 +0300 Subject: [PATCH 19/51] Finally buildable --- .gitignore | 1 + fabric/build.gradle | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/.gitignore b/.gitignore index 5e9e5402..9442545b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .gradle **/build/ !src/**/build/ +**/remappedSrc/ # Ignore Gradle GUI config gradle-app.setting diff --git a/fabric/build.gradle b/fabric/build.gradle index 894d4d34..3773bbe8 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -24,12 +24,24 @@ shadowJar { mergeServiceFiles() } +copyOutput { + from remapJar.archiveFile + into rootProject.file('jars') +} + remapJar { dependsOn shadowJar mustRunAfter shadowJar inputFile = shadowJar.archiveFile archiveBaseName = 'DiscordSRV-Fabric' archiveClassifier = jar.archiveClassifier + + finalizedBy copyOutput // TODO: This currently adds the remapped jar to the jars folder with the shadow jar. The fix for the buildable jar was the artifacts task. +} + +artifacts { + archives remapJar + shadow shadowJar } loom { From 938058f02caa71fd0449485a31ebd2855162621c Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Tue, 14 Jan 2025 06:59:43 +0300 Subject: [PATCH 20/51] Cleanup --- .../discordsrv/fabric/module/chat/FabricDeathModule.java | 6 ------ .../discordsrv/fabric/module/chat/FabricJoinModule.java | 9 ++------- .../discordsrv/fabric/module/chat/FabricQuitModule.java | 8 -------- 3 files changed, 2 insertions(+), 21 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java index 5f5429b2..7d294c0b 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java @@ -25,18 +25,12 @@ import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.fabric.module.AbstractFabricModule; import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents; -import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.translation.GlobalTranslator; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.damage.DamageSource; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import net.minecraft.util.Formatting; -import java.util.Locale; - - public class FabricDeathModule extends AbstractFabricModule { private final FabricDiscordSRV discordSRV; diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java index 209e4895..7315cbdf 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java @@ -21,16 +21,12 @@ import com.discordsrv.api.component.MinecraftComponent; import com.discordsrv.api.events.message.receive.game.JoinMessageReceiveEvent; import com.discordsrv.api.player.DiscordSRVPlayer; -import com.discordsrv.common.feature.bansync.BanSyncModule; import com.discordsrv.common.util.ComponentUtil; import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.fabric.module.AbstractFabricModule; import com.discordsrv.fabric.requiredlinking.FabricRequiredLinkingModule; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; -import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.translation.GlobalTranslator; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; @@ -38,7 +34,6 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; -import java.util.Locale; import java.util.Objects; public class FabricJoinModule extends AbstractFabricModule { @@ -58,14 +53,14 @@ private void onJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSen if (!enabled) return; FabricRequiredLinkingModule module = discordSRV.getModule(FabricRequiredLinkingModule.class); - if(module != null && !module.isLoginCancelled(serverPlayNetworkHandler.player.getUuid())) { + if(module != null && module.isLoginCancelled(serverPlayNetworkHandler.player.getUuid())) { module.removeLoginCancelled(serverPlayNetworkHandler.player.getUuid()); return; } ServerPlayerEntity playerEntity = serverPlayNetworkHandler.player; MinecraftComponent component = getJoinMessage(playerEntity); - boolean firstJoin = !Objects.requireNonNull(minecraftServer.getUserCache()).findByName(serverPlayNetworkHandler.player.getGameProfile().getName()).isPresent(); + boolean firstJoin = Objects.requireNonNull(minecraftServer.getUserCache()).findByName(serverPlayNetworkHandler.player.getGameProfile().getName()).isEmpty(); DiscordSRVPlayer player = discordSRV.playerProvider().player(playerEntity); discordSRV.eventBus().publish( diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java index df3e75c6..bc76fe6c 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java @@ -20,23 +20,16 @@ import com.discordsrv.api.component.MinecraftComponent; import com.discordsrv.api.events.message.receive.game.LeaveMessageReceiveEvent; -import com.discordsrv.api.player.DiscordSRVPlayer; import com.discordsrv.common.util.ComponentUtil; import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.fabric.module.AbstractFabricModule; import com.discordsrv.fabric.player.FabricPlayer; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; -import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.translation.GlobalTranslator; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import net.minecraft.util.Formatting; -import net.minecraft.util.Identifier; - -import java.util.Locale; public class FabricQuitModule extends AbstractFabricModule { private final FabricDiscordSRV discordSRV; @@ -47,7 +40,6 @@ public FabricQuitModule(FabricDiscordSRV discordSRV) { } public void register() { - // First phase ServerPlayConnectionEvents.DISCONNECT.register(this::onDisconnect); } From 13e6a612acf4b8be926021e9cd37dfe056cff557 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Tue, 14 Jan 2025 07:00:22 +0300 Subject: [PATCH 21/51] refactor to command package --- .../src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java | 2 +- .../fabric/{ => command}/game/handler/FabricCommandHandler.java | 2 +- .../fabric/{ => command}/game/sender/FabricCommandSender.java | 2 +- .../main/java/com/discordsrv/fabric/console/FabricConsole.java | 2 +- .../main/java/com/discordsrv/fabric/player/FabricPlayer.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename fabric/src/main/java/com/discordsrv/fabric/{ => command}/game/handler/FabricCommandHandler.java (97%) rename fabric/src/main/java/com/discordsrv/fabric/{ => command}/game/sender/FabricCommandSender.java (97%) diff --git a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java index 2496577c..7665c70c 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java +++ b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java @@ -27,7 +27,7 @@ import com.discordsrv.common.feature.messageforwarding.game.MinecraftToDiscordChatModule; import com.discordsrv.fabric.config.main.FabricConfig; import com.discordsrv.fabric.console.FabricConsole; -import com.discordsrv.fabric.game.handler.FabricCommandHandler; +import com.discordsrv.fabric.command.game.handler.FabricCommandHandler; import com.discordsrv.fabric.module.chat.*; import com.discordsrv.fabric.module.ban.FabricBanModule; import com.discordsrv.fabric.requiredlinking.FabricRequiredLinkingModule; diff --git a/fabric/src/main/java/com/discordsrv/fabric/game/handler/FabricCommandHandler.java b/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java similarity index 97% rename from fabric/src/main/java/com/discordsrv/fabric/game/handler/FabricCommandHandler.java rename to fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java index a295fea3..d183f6c4 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/game/handler/FabricCommandHandler.java +++ b/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package com.discordsrv.fabric.game.handler; +package com.discordsrv.fabric.command.game.handler; import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.common.command.game.abstraction.command.GameCommand; diff --git a/fabric/src/main/java/com/discordsrv/fabric/game/sender/FabricCommandSender.java b/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java similarity index 97% rename from fabric/src/main/java/com/discordsrv/fabric/game/sender/FabricCommandSender.java rename to fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java index f03043bb..2556c399 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/game/sender/FabricCommandSender.java +++ b/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package com.discordsrv.fabric.game.sender; +package com.discordsrv.fabric.command.game.sender; import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.common.command.game.abstraction.sender.ICommandSender; diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java b/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java index 3e20169c..61548c0c 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java +++ b/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java @@ -20,7 +20,7 @@ import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.fabric.console.executor.FabricCommandExecutorProvider; -import com.discordsrv.fabric.game.sender.FabricCommandSender; +import com.discordsrv.fabric.command.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; diff --git a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java index 0d7d6868..4e4c2b45 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java +++ b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java @@ -19,7 +19,7 @@ package com.discordsrv.fabric.player; import com.discordsrv.fabric.FabricDiscordSRV; -import com.discordsrv.fabric.game.sender.FabricCommandSender; +import com.discordsrv.fabric.command.game.sender.FabricCommandSender; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.abstraction.player.provider.model.SkinInfo; From fb4b9abb306d9e925ef6b2f8a68b6c09e7043390 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Tue, 14 Jan 2025 09:12:07 +0300 Subject: [PATCH 22/51] Well I had to do this. --- buildscript/relocations.gradle | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/buildscript/relocations.gradle b/buildscript/relocations.gradle index 4fa722b1..ee7e0389 100644 --- a/buildscript/relocations.gradle +++ b/buildscript/relocations.gradle @@ -42,8 +42,8 @@ 'net.kyori.adventure.ansi', 'net.kyori.adventure.examination', 'net.kyori.adventure.option', - 'net.kyori.adventure.platform', - 'net.kyori.adventure.text.serializer', +// 'net.kyori.adventure.platform', +// 'net.kyori.adventure.text.serializer', // EnhancedLegacyText, MCDiscordReserializer 'dev.vankka.enhancedlegacytext', @@ -78,4 +78,6 @@ shadowJar { // Unrelocate package, in case a platform uses something we normally relocate relocate('com.discordsrv.unrelocate.', '') +// relocate 'com.discordsrv.dependencies.net.kyori.adventure.platform.fabric.', 'net.kyori.adventure.platform.fabric' +// relocate 'com.discordsrv.dependencies.net.kyori.adventure.platform.modcommon.', 'net.kyori.adventure.platform.modcommon' } From 6dec0b793960aa1fedf3bb9a382e5b0861d91dc7 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Tue, 14 Jan 2025 09:12:32 +0300 Subject: [PATCH 23/51] Fix advancement null pointer on crafting recipe unlock --- .../fabric/module/chat/FabricAdvancementModule.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java index 44e90c0b..a5e61d8b 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java @@ -24,6 +24,7 @@ import com.discordsrv.common.util.ComponentUtil; import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.fabric.module.AbstractFabricModule; +import net.minecraft.advancement.Advancement; import net.minecraft.advancement.AdvancementEntry; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Formatting; @@ -43,7 +44,9 @@ public static void onGrant(AdvancementEntry advancementEntry, String criterionNa if (instance == null || !instance.enabled) return; FabricDiscordSRV discordSRV = instance.discordSRV; - String achievement = Formatting.strip(advancementEntry.value().name().get().getString()); + Advancement advancement = advancementEntry.value(); + if(advancement.name().isEmpty()) return; // Usually a crafting recipe. + String achievement = Formatting.strip(advancement.name().get().getString()); MinecraftComponent achievementName = ComponentUtil.fromPlain(achievement); IPlayer player = discordSRV.playerProvider().player(owner); From 88494c29e19d1c73c4745ee7ee2cbfbec5e470b8 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Tue, 14 Jan 2025 09:39:08 +0300 Subject: [PATCH 24/51] Cleanup advancement module and use advancement display --- .../mixin/PlayerAdvancementTrackerMixin.java | 2 +- .../module/chat/FabricAdvancementModule.java | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java b/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java index d04f830b..ba7d7ab1 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java +++ b/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java @@ -35,6 +35,6 @@ public class PlayerAdvancementTrackerMixin { @Inject(method = "grantCriterion", at = @At(value = "INVOKE", target = "Lnet/minecraft/advancement/PlayerAdvancementTracker;onStatusUpdate(Lnet/minecraft/advancement/AdvancementEntry;)V")) public void onGrant(AdvancementEntry advancementEntry, String criterionName, CallbackInfoReturnable cir) { - FabricAdvancementModule.onGrant(advancementEntry, criterionName, cir, owner); + FabricAdvancementModule.onGrant(advancementEntry, owner); } } diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java index a5e61d8b..8635ba0a 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java @@ -28,7 +28,6 @@ import net.minecraft.advancement.AdvancementEntry; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.Formatting; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; public class FabricAdvancementModule extends AbstractFabricModule { private final FabricDiscordSRV discordSRV; @@ -40,21 +39,25 @@ public FabricAdvancementModule(FabricDiscordSRV discordSRV) { instance = this; } - public static void onGrant(AdvancementEntry advancementEntry, String criterionName, CallbackInfoReturnable cir, ServerPlayerEntity owner) { + public static void onGrant(AdvancementEntry advancementEntry, ServerPlayerEntity owner) { if (instance == null || !instance.enabled) return; FabricDiscordSRV discordSRV = instance.discordSRV; Advancement advancement = advancementEntry.value(); - if(advancement.name().isEmpty()) return; // Usually a crafting recipe. - String achievement = Formatting.strip(advancement.name().get().getString()); - MinecraftComponent achievementName = ComponentUtil.fromPlain(achievement); + if(advancement.display().isEmpty() || advancement.name().isEmpty()) return; // Usually a crafting recipe. + String title = Formatting.strip(advancement.display().get().getTitle().getString()); + MinecraftComponent advancementTitle = ComponentUtil.fromPlain(title); + + // TODO: Add description to the event. So we can explain how the player got the advancement. +// String description = Formatting.strip(advancement.display().get().getDescription().getString()); +// MinecraftComponent advancementDescription = ComponentUtil.fromPlain(description); IPlayer player = discordSRV.playerProvider().player(owner); discordSRV.eventBus().publish( new AwardMessageReceiveEvent( null, player, - achievementName, + advancementTitle, null, null, false From dd10abf0e419299dd03149d0819db5234470268e Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Tue, 14 Jan 2025 10:15:16 +0300 Subject: [PATCH 25/51] Block join attempts before connecting to discord with no jank --- .../requiredlinking/PlayerManagerMixin.java | 40 ++++++++++++++++ .../fabric/module/chat/FabricJoinModule.java | 8 ---- .../FabricRequiredLinkingModule.java | 48 ++++++++----------- .../src/main/resources/discordsrv.mixins.json | 3 +- 4 files changed, 62 insertions(+), 37 deletions(-) create mode 100644 fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/PlayerManagerMixin.java diff --git a/fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/PlayerManagerMixin.java b/fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/PlayerManagerMixin.java new file mode 100644 index 00000000..e2a7dd19 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/PlayerManagerMixin.java @@ -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 . + */ + +package com.discordsrv.fabric.mixin.requiredlinking; + +import com.discordsrv.fabric.requiredlinking.FabricRequiredLinkingModule; +import com.mojang.authlib.GameProfile; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.net.SocketAddress; + +@Mixin(net.minecraft.server.PlayerManager.class) +public class PlayerManagerMixin { + + @Inject(method = "checkCanJoin", at = @At("TAIL"), cancellable = true) + public void checkCanJoin(SocketAddress address, GameProfile profile, CallbackInfoReturnable cir) { + Text kickReason = FabricRequiredLinkingModule.checkCanJoin(profile); + + cir.setReturnValue(kickReason); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java index 7315cbdf..31fd98a9 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java @@ -24,7 +24,6 @@ import com.discordsrv.common.util.ComponentUtil; import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.fabric.module.AbstractFabricModule; -import com.discordsrv.fabric.requiredlinking.FabricRequiredLinkingModule; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.minecraft.server.MinecraftServer; @@ -46,18 +45,11 @@ public FabricJoinModule(FabricDiscordSRV discordSRV) { public void register() { ServerPlayConnectionEvents.JOIN.register(this::onJoin); - } private void onJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSender packetSender, MinecraftServer minecraftServer) { if (!enabled) return; - FabricRequiredLinkingModule module = discordSRV.getModule(FabricRequiredLinkingModule.class); - if(module != null && module.isLoginCancelled(serverPlayNetworkHandler.player.getUuid())) { - module.removeLoginCancelled(serverPlayNetworkHandler.player.getUuid()); - return; - } - ServerPlayerEntity playerEntity = serverPlayNetworkHandler.player; MinecraftComponent component = getJoinMessage(playerEntity); boolean firstJoin = Objects.requireNonNull(minecraftServer.getUserCache()).findByName(serverPlayNetworkHandler.player.getGameProfile().getName()).isEmpty(); diff --git a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java index 2f0b7060..678b88f5 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java @@ -25,12 +25,12 @@ import com.discordsrv.common.feature.linking.LinkStore; import com.discordsrv.common.feature.linking.requirelinking.ServerRequireLinkingModule; import com.github.benmanes.caffeine.cache.Cache; -import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import com.mojang.authlib.GameProfile; import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; import net.kyori.adventure.text.Component; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; @@ -40,6 +40,7 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule { + private static FabricRequiredLinkingModule instance; private boolean enabled = false; private final Cache linkCheckRateLimit; @@ -50,7 +51,7 @@ public FabricRequiredLinkingModule(FabricDiscordSRV discordSRV) { .expireAfterWrite(LinkStore.LINKING_CODE_RATE_LIMIT) .build(); - register(); + instance = this; } @Override @@ -65,10 +66,6 @@ public void enable() { this.enabled = true; } - public void register() { - // TODO: mixin into net.minecraft.server.PlayerManager#checkCanJoin - ServerPlayConnectionEvents.INIT.register(this::onPlayerPreLogin); - } @Override public void disable() { @@ -77,33 +74,28 @@ public void disable() { this.enabled = false; } - private final List loginsCancelled = new CopyOnWriteArrayList<>(); - - public boolean isLoginCancelled(UUID playerUUID) { - return loginsCancelled.contains(playerUUID); - } - - public void removeLoginCancelled(UUID playerUUID) { - loginsCancelled.remove(playerUUID); - } - - private void onPlayerPreLogin(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) { - if(!this.enabled) return; + @Nullable + public static Text checkCanJoin(GameProfile profile) { + if (instance == null || (instance.discordSRV != null && instance.discordSRV.status() != DiscordSRV.Status.CONNECTED)) { + return Text.of("Currently unavailable to check link status because the server is still connecting to Discord.\n\nTry again in a minute."); + } + if (!instance.enabled) return null; - ServerRequiredLinkingConfig config = config(); + FabricDiscordSRV discordSRV = instance.discordSRV; + ServerRequiredLinkingConfig config = instance.config(); if (!config.enabled || config.action != ServerRequiredLinkingConfig.Action.KICK) { - return; + return null; } - ServerPlayerEntity player = serverPlayNetworkHandler.player; - UUID playerUUID = player.getUuid(); - String playerName = player.getName().getString(); + UUID playerUUID = profile.getId(); + String playerName = profile.getName(); - Component kickReason = getBlockReason(playerUUID, playerName, true).join(); + Component kickReason = instance.getBlockReason(playerUUID, playerName, true).join(); if (kickReason != null) { - serverPlayNetworkHandler.disconnect(MinecraftServerAudiences.of(minecraftServer).asNative(kickReason)); - loginsCancelled.add(playerUUID); + return MinecraftServerAudiences.of(discordSRV.getServer()).asNative(kickReason); } + + return null; } @Override diff --git a/fabric/src/main/resources/discordsrv.mixins.json b/fabric/src/main/resources/discordsrv.mixins.json index da069047..f05764c0 100644 --- a/fabric/src/main/resources/discordsrv.mixins.json +++ b/fabric/src/main/resources/discordsrv.mixins.json @@ -4,7 +4,8 @@ "compatibilityLevel": "JAVA_21", "mixins": [ "PlayerAdvancementTrackerMixin", - "ban.BanCommandMixin" + "ban.BanCommandMixin", + "requiredlinking.PlayerManagerMixin" ], "injectors": { "defaultRequire": 1 From 5e6499d849946ea1df4914fd848f0a45603ce205 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Wed, 15 Jan 2025 14:18:46 +0300 Subject: [PATCH 26/51] Freeze action in required linking module --- fabric/build.gradle | 1 + .../requiredlinking/CommandManagerMixin.java | 37 +++ .../ServerPlayNetworkHandlerMixin.java | 41 +++ .../FabricRequiredLinkingModule.java | 303 +++++++++--------- .../main/resources/discordsrv.accesswidener | 7 + .../src/main/resources/discordsrv.mixins.json | 4 +- fabric/src/main/resources/fabric.mod.json | 1 + 7 files changed, 248 insertions(+), 146 deletions(-) create mode 100644 fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/CommandManagerMixin.java create mode 100644 fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/ServerPlayNetworkHandlerMixin.java create mode 100644 fabric/src/main/resources/discordsrv.accesswidener diff --git a/fabric/build.gradle b/fabric/build.gradle index 3773bbe8..f9f33e74 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -46,6 +46,7 @@ artifacts { loom { serverOnlyMinecraftJar() + accessWidenerPath = file('src/main/resources/discordsrv.accesswidener') } repositories { diff --git a/fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/CommandManagerMixin.java b/fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/CommandManagerMixin.java new file mode 100644 index 00000000..97840fa8 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/CommandManagerMixin.java @@ -0,0 +1,37 @@ +/* + * 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 . + */ + +package com.discordsrv.fabric.mixin.requiredlinking; + +import com.discordsrv.fabric.requiredlinking.FabricRequiredLinkingModule; +import com.mojang.brigadier.ParseResults; +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.ServerCommandSource; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(CommandManager.class) +public class CommandManagerMixin { + + @Inject(method = "execute", at = @At("HEAD"), cancellable = true) + private void execute(ParseResults parseResults, String command, CallbackInfo ci) { + FabricRequiredLinkingModule.onCommandExecute(parseResults, command, ci); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/ServerPlayNetworkHandlerMixin.java b/fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/ServerPlayNetworkHandlerMixin.java new file mode 100644 index 00000000..cd4ae0cd --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/ServerPlayNetworkHandlerMixin.java @@ -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 . + */ + +package com.discordsrv.fabric.mixin.requiredlinking; + +import com.discordsrv.fabric.requiredlinking.FabricRequiredLinkingModule; +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerPlayNetworkHandler.class) +public class ServerPlayNetworkHandlerMixin { + + @Shadow + public ServerPlayerEntity player; + + @Inject(method = "onPlayerMove", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerEntity;getServerWorld()Lnet/minecraft/server/world/ServerWorld;", ordinal = 1), cancellable = true) + private void onPlayerMove(PlayerMoveC2SPacket packet, CallbackInfo ci) { + FabricRequiredLinkingModule.onPlayerMove(player, packet, ci); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java index 678b88f5..b11b7311 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java @@ -24,13 +24,25 @@ import com.discordsrv.common.config.main.linking.ServerRequiredLinkingConfig; import com.discordsrv.common.feature.linking.LinkStore; import com.discordsrv.common.feature.linking.requirelinking.ServerRequireLinkingModule; +import com.discordsrv.fabric.player.FabricPlayer; import com.github.benmanes.caffeine.cache.Cache; import com.mojang.authlib.GameProfile; +import com.mojang.brigadier.ParseResults; +import net.fabricmc.fabric.api.message.v1.ServerMessageEvents; +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; import net.kyori.adventure.text.Component; +import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerConfigurationNetworkHandler; +import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.List; import java.util.Map; @@ -51,6 +63,8 @@ public FabricRequiredLinkingModule(FabricDiscordSRV discordSRV) { .expireAfterWrite(LinkStore.LINKING_CODE_RATE_LIMIT) .build(); + register(); + instance = this; } @@ -66,6 +80,20 @@ public void enable() { this.enabled = true; } + public void register() { + ServerMessageEvents.ALLOW_CHAT_MESSAGE.register((text, player, parameters) -> { + // True if the message should be sent + if (isFrozen(player)) { + player.sendMessage(frozen.get(player.getUuid())); + return false; + } + return true; + }); + + ServerConfigurationConnectionEvents.CONFIGURE.register(this::onPlayerPreLogin); + ServerPlayConnectionEvents.JOIN.register(this::onPlayerJoin); + ServerPlayConnectionEvents.DISCONNECT.register(this::onPlayerQuit); + } @Override public void disable() { @@ -74,6 +102,32 @@ public void disable() { this.enabled = false; } + @Override + public void recheck(IPlayer player) { + getBlockReason(player.uniqueId(), player.username(), false).whenComplete((component, throwable) -> { + if (component != null) { + switch (action()) { + case KICK: + player.kick(component); + break; + case FREEZE: + freeze(player, component); + break; + } + } else if (action() == ServerRequiredLinkingConfig.Action.FREEZE) { + frozen.remove(player.uniqueId()); + } + }); + } + + public ServerRequiredLinkingConfig.Action action() { + return config().action; + } + + // + // Kick + // + @Nullable public static Text checkCanJoin(GameProfile profile) { if (instance == null || (instance.discordSRV != null && instance.discordSRV.status() != DiscordSRV.Status.CONNECTED)) { @@ -98,30 +152,8 @@ public static Text checkCanJoin(GameProfile profile) { return null; } - @Override - public void recheck(IPlayer player) { - getBlockReason(player.uniqueId(), player.username(), false).whenComplete((component, throwable) -> { - if (component != null) { - switch (action()) { - case KICK: - player.kick(component); - break; - case FREEZE: - freeze(player, component); - break; - } - } else if (action() == ServerRequiredLinkingConfig.Action.FREEZE) { - frozen.remove(player.uniqueId()); - } - }); - } - - public ServerRequiredLinkingConfig.Action action() { - return config().action; - } - // - // Freeze - TODO: Not implemented yet + // Freeze // private final Map frozen = new ConcurrentHashMap<>(); @@ -136,49 +168,41 @@ private void freeze(IPlayer player, Component blockReason) { player.sendMessage(blockReason); } -// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) -// public void onAsyncPlayerPreLogin(AsyncPlayerPreLoginEvent event) { -// if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) { -// return; -// } -// -// UUID playerUUID = event.getUniqueId(); -// loginsHandled.add(playerUUID); -// handleLogin(playerUUID, event.getName()); -// } -// -// @EventHandler(priority = EventPriority.MONITOR) -// public void onPlayerLogin(PlayerLoginEvent event) { -// if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) { -// frozen.remove(event.getPlayer().getUniqueId()); -// } -// } -// -// @EventHandler(priority = EventPriority.LOWEST) -// public void onPlayerJoinLowest(PlayerJoinEvent event) { -// Player player = event.getPlayer(); -// UUID playerUUID = player.getUniqueId(); -// if (!loginsHandled.remove(playerUUID)) { -// handleLogin(playerUUID, player.getName()); -// } -// } -// -// @EventHandler(priority = EventPriority.MONITOR) -// public void onPlayerJoinMonitor(PlayerJoinEvent event) { -// UUID playerUUID = event.getPlayer().getUniqueId(); -// -// Component blockReason = frozen.get(playerUUID); -// if (blockReason == null) { -// return; -// } -// -// IPlayer srvPlayer = discordSRV.playerProvider().player(playerUUID); -// if (srvPlayer == null) { -// throw new IllegalStateException("Player not available: " + playerUUID); -// } -// -// srvPlayer.sendMessage(blockReason); -// } + private void onPlayerPreLogin(ServerConfigurationNetworkHandler handler, MinecraftServer minecraftServer) { + if(!enabled) return; + UUID playerUUID = handler.getDebugProfile().getId(); + loginsHandled.add(playerUUID); + handleLogin(playerUUID, handler.getDebugProfile().getName()); + } + + + private void onPlayerJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSender packetSender, MinecraftServer minecraftServer) { + if(!enabled) return; + UUID playerUUID = serverPlayNetworkHandler.player.getUuid(); + + if(!loginsHandled.contains(playerUUID)) { + handleLogin(playerUUID, serverPlayNetworkHandler.player.getName().getString()); + } + + Component blockReason = frozen.get(playerUUID); + if (blockReason == null) { + return; + } + + IPlayer srvPlayer = discordSRV.playerProvider().player(playerUUID); + if (srvPlayer == null) { + throw new IllegalStateException("Player not available: " + playerUUID); + } + + srvPlayer.sendMessage(blockReason); + } + + private void onPlayerQuit(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) { + if(!enabled) return; + UUID playerUUID = serverPlayNetworkHandler.player.getUuid(); + loginsHandled.remove(playerUUID); + frozen.remove(playerUUID); + } private void handleLogin(UUID playerUUID, String username) { if (discordSRV.isShutdown()) { @@ -202,83 +226,72 @@ private void handleLogin(UUID playerUUID, String username) { } } -// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) -// public void onPlayerMove(PlayerMoveEvent event) { -// Component freezeReason = frozen.get(event.getPlayer().getUniqueId()); -// if (freezeReason == null) { -// return; -// } -// -// Location from = event.getFrom(), to = event.getTo(); -// if (from.getWorld().getName().equals(to.getWorld().getName()) -// && from.getBlockX() == to.getBlockX() -// && from.getBlockZ() == to.getBlockZ() -// && from.getBlockY() >= to.getBlockY()) { -// return; -// } -// -// event.setTo( -// new Location( -// from.getWorld(), -// from.getBlockX() + 0.5, -// from.getBlockY(), -// from.getBlockZ() + 0.5, -// from.getYaw(), -// from.getPitch() -// ) -// ); -// -// IPlayer player = discordSRV.playerProvider().player(event.getPlayer()); -// player.sendMessage(freezeReason); -// } -// -// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) -// public void onAsyncPlayerChat(AsyncPlayerChatEvent event) { -// Component freezeReason = frozen.get(event.getPlayer().getUniqueId()); -// if (freezeReason == null) { -// event.getRecipients().removeIf(this::isFrozen); -// return; -// } -// -// event.setCancelled(true); -// -// IPlayer player = discordSRV.playerProvider().player(event.getPlayer()); -// player.sendMessage(freezeReason); -// } -// -// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) -// public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { -// if (!isFrozen(event.getPlayer())) { -// return; -// } -// -// event.setCancelled(true); -// -// String message = event.getMessage(); -// if (message.startsWith("/")) message = message.substring(1); -// if (message.equals("discord link") || message.equals("link")) { -// IPlayer player = discordSRV.playerProvider().player(event.getPlayer()); -// -// if (linkCheckRateLimit.getIfPresent(player.uniqueId()) != null) { -// player.sendMessage(discordSRV.messagesConfig(player).pleaseWaitBeforeRunningThatCommandAgain.asComponent()); -// return; -// } -// linkCheckRateLimit.put(player.uniqueId(), true); -// -// player.sendMessage(Component.text("Checking...")); -// -// UUID uuid = player.uniqueId(); -// getBlockReason(uuid, player.username(), false).whenComplete((reason, t) -> { -// if (t != null) { -// return; -// } -// -// if (reason == null) { -// frozen.remove(uuid); -// } else { -// freeze(player, reason); -// } -// }); -// } -// } + public static void onPlayerMove(ServerPlayerEntity player, PlayerMoveC2SPacket packet, CallbackInfo ci) { + if(instance == null || !instance.enabled) return; + Component freezeReason = instance.frozen.get(player.getUuid()); + if (freezeReason == null) { + return; + } + + double d = ServerPlayNetworkHandler.clampHorizontal(packet.getX(player.getX())); + double e = ServerPlayNetworkHandler.clampVertical(packet.getY(player.getY())); + double f = ServerPlayNetworkHandler.clampHorizontal(packet.getZ(player.getZ())); + double i = player.getX(); + double j = player.getY(); + double k = player.getZ(); + double l = d - player.networkHandler.lastTickX; + double m = e - player.networkHandler.lastTickY; + double n = f - player.networkHandler.lastTickZ; + // If the player last position is the same. Don't move the player + if (l * l + m * m + n * n > 0.0001) { + player.networkHandler.requestTeleport(i, j, k, player.getYaw(), player.getPitch()); + IPlayer iPlayer = instance.discordSRV.playerProvider().player(player); + iPlayer.sendMessage(freezeReason); + + } + + ci.cancel(); + } + + public static void onCommandExecute(ParseResults parseResults, String command, CallbackInfo ci) { + if(instance == null || !instance.enabled) return; + FabricDiscordSRV discordSRV = instance.discordSRV; + ServerPlayerEntity playerEntity = parseResults.getContext().getSource().getPlayer(); + if(playerEntity == null) return; + + if (!instance.isFrozen(playerEntity)) { + return; + } + + if(command.startsWith("/")) command = command.substring(1); + if(command.equals("discord link") || command.equals("link")) { + + FabricPlayer player = discordSRV.playerProvider().player(playerEntity); + + UUID uuid = player.uniqueId(); + + if (instance.linkCheckRateLimit.getIfPresent(uuid) != null) { + player.sendMessage(discordSRV.messagesConfig(player).pleaseWaitBeforeRunningThatCommandAgain.asComponent()); + return; + } + instance.linkCheckRateLimit.put(uuid, true); + + player.sendMessage(discordSRV.messagesConfig(player).checkingLinkStatus.asComponent()); + + instance.getBlockReason(uuid, player.username(), false).whenComplete((reason, t) -> { + if (t != null) { + return; + } + + if (reason == null) { + instance.frozen.remove(uuid); + player.sendMessage(discordSRV.messagesConfig(player).nowLinked1st.asComponent()); + } else { + instance.freeze(player, reason); + } + }); + } + + ci.cancel(); + } } diff --git a/fabric/src/main/resources/discordsrv.accesswidener b/fabric/src/main/resources/discordsrv.accesswidener new file mode 100644 index 00000000..1fc22989 --- /dev/null +++ b/fabric/src/main/resources/discordsrv.accesswidener @@ -0,0 +1,7 @@ +accessWidener v1 named +accessible method net/minecraft/server/network/ServerPlayNetworkHandler clampHorizontal (D)D +accessible method net/minecraft/server/network/ServerPlayNetworkHandler clampVertical (D)D + +accessible field net/minecraft/server/network/ServerPlayNetworkHandler lastTickX D +accessible field net/minecraft/server/network/ServerPlayNetworkHandler lastTickY D +accessible field net/minecraft/server/network/ServerPlayNetworkHandler lastTickZ D \ No newline at end of file diff --git a/fabric/src/main/resources/discordsrv.mixins.json b/fabric/src/main/resources/discordsrv.mixins.json index f05764c0..9f6cd60c 100644 --- a/fabric/src/main/resources/discordsrv.mixins.json +++ b/fabric/src/main/resources/discordsrv.mixins.json @@ -5,7 +5,9 @@ "mixins": [ "PlayerAdvancementTrackerMixin", "ban.BanCommandMixin", - "requiredlinking.PlayerManagerMixin" + "requiredlinking.CommandManagerMixin", + "requiredlinking.PlayerManagerMixin", + "requiredlinking.ServerPlayNetworkHandlerMixin" ], "injectors": { "defaultRequire": 1 diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index f2e0fe74..9dd44fb1 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -21,6 +21,7 @@ "file": "META-INF/jars/adventure-platform-mod-shared-fabric-repack-6.1.0.jar" } ], + "accessWidener": "discordsrv.accesswidener", "depends": { "fabricloader": ">=${LOADER_VERSION}", "fabric": "*", From 61acd0a718171100690add189a5e7e42f943f898 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Thu, 16 Jan 2025 10:53:00 +0300 Subject: [PATCH 27/51] Fabric API 0.114.3 --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index f1772537..5bfcc0c4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -46,7 +46,7 @@ dependencyResolutionManagement { 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-api', 'net.fabricmc.fabric-api', 'fabric-api').version('0.114.3+1.21.4') library('fabric-permissions-api', 'me.lucko', 'fabric-permissions-api').version('0.3.3') // DependencyDownload From 40da11747d739437f6e1cd5fba6dadd47be43813 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Thu, 16 Jan 2025 10:53:39 +0300 Subject: [PATCH 28/51] Commands were working. But I was an idiot. Command arguments are bugged tho --- .../fabric/command/game/handler/FabricCommandHandler.java | 2 +- .../fabric/command/game/sender/FabricCommandSender.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java b/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java index d183f6c4..be276204 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java +++ b/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java @@ -49,6 +49,6 @@ private ICommandSender getSender(CommandSource source) { @Override public void registerCommand(GameCommand command) { LiteralCommandNode node = BrigadierUtil.convertToBrigadier(command, this::getSender); - discordSRV.getServer().getCommandManager().getDispatcher().getRoot().addChild(node); + discordSRV.getServer().getCommandManager().getDispatcher().register(node.createBuilder()); } } diff --git a/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java b/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java index 2556c399..a9fae298 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java +++ b/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java @@ -38,7 +38,7 @@ public FabricCommandSender(FabricDiscordSRV discordSRV, ServerCommandSource comm @Override public boolean hasPermission(String permission) { - return Permissions.check(commandSource, permission); + return Permissions.check(commandSource, permission, 4); } @Override From e1179c408c587a813ab2abc3481358f2f5a87e3c Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Thu, 16 Jan 2025 11:15:53 +0300 Subject: [PATCH 29/51] Working command arguments --- .../fabric/command/game/handler/FabricCommandHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java b/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java index be276204..d183f6c4 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java +++ b/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java @@ -49,6 +49,6 @@ private ICommandSender getSender(CommandSource source) { @Override public void registerCommand(GameCommand command) { LiteralCommandNode node = BrigadierUtil.convertToBrigadier(command, this::getSender); - discordSRV.getServer().getCommandManager().getDispatcher().register(node.createBuilder()); + discordSRV.getServer().getCommandManager().getDispatcher().getRoot().addChild(node); } } From baa19fad22140439f2ddc64388de2bb037329e30 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Thu, 16 Jan 2025 12:08:54 +0300 Subject: [PATCH 30/51] Get manifest url --- .../discordsrv/fabric/FabricDiscordSRV.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java index 7665c70c..941c4fd5 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java +++ b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java @@ -38,10 +38,15 @@ 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.fabricmc.loader.api.FabricLoader; import net.minecraft.server.MinecraftServer; import org.jetbrains.annotations.NotNull; -import java.net.URL; +import java.io.IOException; +import java.net.*; +import java.nio.file.Path; +import java.security.CodeSource; +import java.util.NoSuchElementException; import java.util.jar.JarFile; public class FabricDiscordSRV extends AbstractDiscordSRV { @@ -92,17 +97,16 @@ protected void enable() throws Throwable { registerModule(FabricBanModule::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"); -// } + // Referenced from ManifestUtil in Fabric API + try { + CodeSource codeSource = getClass().getProtectionDomain().getCodeSource(); + return URI.create("jar:" + codeSource.getLocation().toString() + "!/" + JarFile.MANIFEST_NAME).toURL(); + } catch (MalformedURLException e) { + this.logger().error("Failed to get manifest URL", e); + return null; + } } public FabricModManager getModManager() { From 6bd6ed2c7c194ed5e8799c5b000905ea7d985851 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Thu, 16 Jan 2025 12:24:22 +0300 Subject: [PATCH 31/51] Cleaning up the pull request from random changes --- .gitignore | 6 ++++-- buildscript/relocations.gradle | 3 --- .../common/core/storage/impl/sql/file/H2Storage.java | 1 - 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 9442545b..3cfd7618 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ .gradle **/build/ !src/**/build/ -**/remappedSrc/ # Ignore Gradle GUI config gradle-app.setting @@ -42,4 +41,7 @@ hs_err_pid* # run-* Gradle tasks **/loader/run/ **/velocity/run/ -**/fabric/run/ \ No newline at end of file +**/fabric/run + +# Fabric mapping migration +**/fabric/remappedSrc \ No newline at end of file diff --git a/buildscript/relocations.gradle b/buildscript/relocations.gradle index ee7e0389..58be7b2f 100644 --- a/buildscript/relocations.gradle +++ b/buildscript/relocations.gradle @@ -69,7 +69,6 @@ // Webhooks 'club.minnced', 'org.json', - ].each { tasks.shadowJar.relocate it, 'com.discordsrv.dependencies.' + it tasks.generateRuntimeDownloadResourceForRuntimeDownloadOnly.relocate it, 'com.discordsrv.dependencies.' + it @@ -78,6 +77,4 @@ shadowJar { // Unrelocate package, in case a platform uses something we normally relocate relocate('com.discordsrv.unrelocate.', '') -// relocate 'com.discordsrv.dependencies.net.kyori.adventure.platform.fabric.', 'net.kyori.adventure.platform.fabric' -// relocate 'com.discordsrv.dependencies.net.kyori.adventure.platform.modcommon.', 'net.kyori.adventure.platform.modcommon' } diff --git a/common/src/main/java/com/discordsrv/common/core/storage/impl/sql/file/H2Storage.java b/common/src/main/java/com/discordsrv/common/core/storage/impl/sql/file/H2Storage.java index 19414773..03764652 100644 --- a/common/src/main/java/com/discordsrv/common/core/storage/impl/sql/file/H2Storage.java +++ b/common/src/main/java/com/discordsrv/common/core/storage/impl/sql/file/H2Storage.java @@ -52,7 +52,6 @@ public void initialize() { try { Class clazz = classLoader.loadClass("org.h2.jdbc.JdbcConnection"); - Constructor constructor = clazz.getConstructor( String.class, // url Properties.class, // info From e1929e51037d7c8c78855e0bcc84a8e42229b256 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Fri, 17 Jan 2025 01:46:41 +0300 Subject: [PATCH 32/51] Block addPlayer and removePlayer if unsubscribed --- .../fabric/player/FabricPlayerProvider.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java index 1acd25c8..eda33879 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java +++ b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java @@ -26,7 +26,10 @@ import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; +import java.util.UUID; + public class FabricPlayerProvider extends AbstractPlayerProvider { + private boolean enabled = false; public FabricPlayerProvider(FabricDiscordSRV discordSRV) { super(discordSRV); @@ -37,6 +40,8 @@ public FabricPlayerProvider(FabricDiscordSRV discordSRV) { @Override public void subscribe() { + enabled = true; + // Add players that are already connected for (ServerPlayerEntity player : discordSRV.getServer().getPlayerManager().getPlayerList()) { addPlayer(player, true); @@ -45,9 +50,7 @@ public void subscribe() { @Override public void unsubscribe() { - for (ServerPlayerEntity player : discordSRV.getServer().getPlayerManager().getPlayerList()) { - removePlayer(player.getUuid()); - } + enabled = false; } private void onConnection(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSender packetSender, MinecraftServer minecraftServer) { @@ -55,13 +58,19 @@ private void onConnection(ServerPlayNetworkHandler serverPlayNetworkHandler, Pac } private void onDisconnect(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) { - removePlayer(serverPlayNetworkHandler.player.getUuid()); + removePlayer(serverPlayNetworkHandler.player); } private void addPlayer(ServerPlayerEntity player, boolean initial) { + if(!enabled) return; addPlayer(player.getUuid(), new FabricPlayer(discordSRV, player), initial); } + private void removePlayer(ServerPlayerEntity player) { + if(!enabled) return; + removePlayer(player.getUuid()); + } + public FabricPlayer player(ServerPlayerEntity player) { FabricPlayer srvPlayer = player(player.getUuid()); if (srvPlayer == null) { From d98e12f241aa3874ecbcc0f97ad695d96d6bf0f5 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Fri, 17 Jan 2025 01:47:28 +0300 Subject: [PATCH 33/51] Set correct license --- fabric/src/main/resources/fabric.mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 9dd44fb1..d8e1fc29 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -6,7 +6,7 @@ "description": "", "authors": [], "contact": {}, - "license": "All-Rights-Reserved", + "license": "GPLv3", "environment": "server", "entrypoints": { "server": [ From 01287a37bdac6145bd203d3643f37ea69119ee97 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Fri, 17 Jan 2025 02:02:47 +0300 Subject: [PATCH 34/51] Handling ban pardon --- .../fabric/mixin/ban/PardonCommandMixin.java | 41 +++++++++++++++++++ .../fabric/module/ban/FabricBanModule.java | 17 ++++---- .../src/main/resources/discordsrv.mixins.json | 1 + 3 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 fabric/src/main/java/com/discordsrv/fabric/mixin/ban/PardonCommandMixin.java diff --git a/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/PardonCommandMixin.java b/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/PardonCommandMixin.java new file mode 100644 index 00000000..1ac62b3a --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/PardonCommandMixin.java @@ -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 . + */ + +package com.discordsrv.fabric.mixin.ban; + +import com.discordsrv.fabric.module.ban.FabricBanModule; +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.dedicated.command.BanCommand; +import net.minecraft.server.dedicated.command.PardonCommand; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Collection; + +@Mixin(PardonCommand.class) +public class PardonCommandMixin { + + @Inject(method = "pardon", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/BannedPlayerList;remove(Ljava/lang/Object;)V")) + private static void pardon(ServerCommandSource source, Collection targets, CallbackInfoReturnable cir, @Local GameProfile gameProfile) { + FabricBanModule.onPardon(gameProfile); + } +} diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java index aadbb1c6..50f77123 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java @@ -56,6 +56,7 @@ public void enable() { } public static void onBan(GameProfile gameProfile) { + if (instance == null) return; FabricDiscordSRV discordSRV = instance.discordSRV; BanSyncModule module = discordSRV.getModule(BanSyncModule.class); if (module != null) { @@ -64,12 +65,19 @@ public static void onBan(GameProfile gameProfile) { } } + public static void onPardon(GameProfile gameProfile) { + if (instance == null) return; + FabricDiscordSRV discordSRV = instance.discordSRV; + BanSyncModule module = discordSRV.getModule(BanSyncModule.class); + if (module != null) instance.removeBan(gameProfile.getId()).complete(null); + } + @Override public CompletableFuture<@Nullable Punishment> getBan(@NotNull UUID playerUUID) { BannedPlayerList banList = discordSRV.getServer().getPlayerManager().getUserBanList(); Optional gameProfile = Objects.requireNonNull(discordSRV.getServer().getUserCache()).getByUuid(playerUUID); - if (!gameProfile.isPresent()) { + if (gameProfile.isEmpty()) { return CompletableFuture.completedFuture(null); } @@ -94,11 +102,6 @@ public CompletableFuture addBan( @NotNull MinecraftComponent punisher ) { try { - String reasonLegacy = reason != null ? ComponentUtil.fromAPI(reason).toString() : null; - String punisherLegacy = ComponentUtil.fromAPI(punisher).toString(); - - BannedPlayerList banList = discordSRV.getServer().getPlayerManager().getUserBanList(); - discordSRV.getServer().getPlayerManager().getUserBanList().add(new BannedPlayerEntry( discordSRV.getServer().getUserCache().getByUuid(playerUUID).get(), null, @@ -123,7 +126,7 @@ public CompletableFuture removeBan(@NotNull UUID playerUUID) { BannedPlayerList banList = discordSRV.getServer().getPlayerManager().getUserBanList(); Optional gameProfile = Objects.requireNonNull(discordSRV.getServer().getUserCache()).getByUuid(playerUUID); - if (!gameProfile.isPresent()) { + if (gameProfile.isEmpty()) { return CompletableFuture.completedFuture(null); } diff --git a/fabric/src/main/resources/discordsrv.mixins.json b/fabric/src/main/resources/discordsrv.mixins.json index 9f6cd60c..81e555c0 100644 --- a/fabric/src/main/resources/discordsrv.mixins.json +++ b/fabric/src/main/resources/discordsrv.mixins.json @@ -5,6 +5,7 @@ "mixins": [ "PlayerAdvancementTrackerMixin", "ban.BanCommandMixin", + "ban.PardonCommandMixin", "requiredlinking.CommandManagerMixin", "requiredlinking.PlayerManagerMixin", "requiredlinking.ServerPlayNetworkHandlerMixin" From aaa2b322ff400b337a22bd3086bcaf288f63b082 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Fri, 17 Jan 2025 02:25:24 +0300 Subject: [PATCH 35/51] Clean up freeze movement logic --- .../FabricRequiredLinkingModule.java | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java index b11b7311..bad76fa2 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java @@ -41,6 +41,7 @@ import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -233,23 +234,16 @@ public static void onPlayerMove(ServerPlayerEntity player, PlayerMoveC2SPacket p return; } - double d = ServerPlayNetworkHandler.clampHorizontal(packet.getX(player.getX())); - double e = ServerPlayNetworkHandler.clampVertical(packet.getY(player.getY())); - double f = ServerPlayNetworkHandler.clampHorizontal(packet.getZ(player.getZ())); - double i = player.getX(); - double j = player.getY(); - double k = player.getZ(); - double l = d - player.networkHandler.lastTickX; - double m = e - player.networkHandler.lastTickY; - double n = f - player.networkHandler.lastTickZ; - // If the player last position is the same. Don't move the player - if (l * l + m * m + n * n > 0.0001) { - player.networkHandler.requestTeleport(i, j, k, player.getYaw(), player.getPitch()); - IPlayer iPlayer = instance.discordSRV.playerProvider().player(player); - iPlayer.sendMessage(freezeReason); - + BlockPos from = player.getBlockPos(); + BlockPos to = new BlockPos((int) packet.getX(player.getX()), (int) packet.getY(player.getY()), (int) packet.getZ(player.getZ())); + if(from.getX() == to.getX() && from.getY() >= to.getY() && from.getZ() == to.getZ()) { + return; } + player.requestTeleport(from.getX() + 0.5, from.getY(), from.getZ() + 0.5); + IPlayer iPlayer = instance.discordSRV.playerProvider().player(player); + iPlayer.sendMessage(freezeReason); + ci.cancel(); } From 37011ab7b8ad2d17ece6a689078df19457396bd2 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Fri, 17 Jan 2025 02:45:28 +0300 Subject: [PATCH 36/51] Remove unnecessary copied proxy logic --- .../fabric/console/FabricConsole.java | 6 +-- .../executor/FabricCommandExecutor.java | 11 +---- .../FabricCommandExecutorProvider.java | 40 ------------------- 3 files changed, 5 insertions(+), 52 deletions(-) delete mode 100644 fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutorProvider.java diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java b/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java index 61548c0c..9b8095f1 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java +++ b/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java @@ -19,22 +19,22 @@ package com.discordsrv.fabric.console; import com.discordsrv.fabric.FabricDiscordSRV; -import com.discordsrv.fabric.console.executor.FabricCommandExecutorProvider; import com.discordsrv.fabric.command.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; +import com.discordsrv.fabric.console.executor.FabricCommandExecutor; public class FabricConsole extends FabricCommandSender implements Console { private final LoggingBackend loggingBackend; - private final FabricCommandExecutorProvider executorProvider; + private final CommandExecutorProvider executorProvider; public FabricConsole(FabricDiscordSRV discordSRV) { super(discordSRV, discordSRV.getServer().getCommandSource()); this.loggingBackend = Log4JLoggerImpl.getRoot(); - this.executorProvider = new FabricCommandExecutorProvider(discordSRV); + this.executorProvider = consumer -> new FabricCommandExecutor(discordSRV); } @Override diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java index abe66336..0d986698 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java +++ b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java @@ -19,24 +19,17 @@ 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 componentConsumer) { + public FabricCommandExecutor(FabricDiscordSRV discordSRV) { this.discordSRV = discordSRV; - this.source = (ServerCommandSource) new AdventureCommandExecutorProxy( - discordSRV.getServer().getCommandSource(), - componentConsumer - ).getProxy(); + this.source = discordSRV.getServer().getCommandSource(); } @Override diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutorProvider.java b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutorProvider.java deleted file mode 100644 index 1c005011..00000000 --- a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutorProvider.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 . - */ - -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 componentConsumer) { - return new FabricCommandExecutor(discordSRV, componentConsumer); - } -} From 0f60d6edf468c2ffb27b2f20e716938e33212a9b Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Fri, 17 Jan 2025 07:30:25 +0300 Subject: [PATCH 37/51] Game command execution autocompletion --- .../GameCommandExecutionConditionConfig.java | 4 +- .../discordsrv/fabric/FabricDiscordSRV.java | 15 +- .../FabricGameCommandExecutionHelper.java | 146 ++++++++++++++++++ 3 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java diff --git a/common/src/main/java/com/discordsrv/common/config/main/generic/GameCommandExecutionConditionConfig.java b/common/src/main/java/com/discordsrv/common/config/main/generic/GameCommandExecutionConditionConfig.java index c945ebb8..6c95578a 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/generic/GameCommandExecutionConditionConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/generic/GameCommandExecutionConditionConfig.java @@ -127,9 +127,9 @@ public boolean isAcceptableCommand(DiscordGuildMember member, DiscordUser user, for (String configCommand : commands) { if (isCommandMatch(configCommand, command, suggestions, helper) != blacklist) { - return true; + return blacklist; } } - return false; + return !blacklist; } } diff --git a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java index 941c4fd5..af3666a4 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java +++ b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java @@ -18,6 +18,7 @@ package com.discordsrv.fabric; +import com.discordsrv.common.command.game.abstraction.GameCommandExecutionHelper; import com.discordsrv.common.config.configurate.manager.ConnectionConfigManager; import com.discordsrv.common.config.configurate.manager.MainConfigManager; import com.discordsrv.common.config.configurate.manager.MessagesConfigManager; @@ -25,6 +26,7 @@ import com.discordsrv.common.config.connection.ConnectionConfig; import com.discordsrv.common.config.messages.MessagesConfig; import com.discordsrv.common.feature.messageforwarding.game.MinecraftToDiscordChatModule; +import com.discordsrv.fabric.command.game.FabricGameCommandExecutionHelper; import com.discordsrv.fabric.config.main.FabricConfig; import com.discordsrv.fabric.console.FabricConsole; import com.discordsrv.fabric.command.game.handler.FabricCommandHandler; @@ -38,15 +40,12 @@ 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.fabricmc.loader.api.FabricLoader; import net.minecraft.server.MinecraftServer; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.io.IOException; import java.net.*; -import java.nio.file.Path; import java.security.CodeSource; -import java.util.NoSuchElementException; import java.util.jar.JarFile; public class FabricDiscordSRV extends AbstractDiscordSRV { @@ -61,6 +60,8 @@ public class FabricDiscordSRV extends AbstractDiscordSRV configManager; private final MessagesConfigManager messagesConfigManager; + private final FabricGameCommandExecutionHelper executionHelper; + public FabricDiscordSRV(DiscordSRVFabricBootstrap bootstrap) { super(bootstrap); @@ -69,6 +70,7 @@ public FabricDiscordSRV(DiscordSRVFabricBootstrap bootstrap) { this.playerProvider = new FabricPlayerProvider(this); this.modManager = new FabricModManager(this); this.commandHandler = new FabricCommandHandler(this); + this.executionHelper = new FabricGameCommandExecutionHelper(this); // Config this.connectionConfigManager = new ConnectionConfigManager<>(this, ConnectionConfig::new); @@ -166,4 +168,9 @@ public MainConfigManager configManager() { public MessagesConfigManager messagesConfigManager() { return messagesConfigManager; } + + @Override + public @Nullable GameCommandExecutionHelper executeHelper() { + return executionHelper; + } } diff --git a/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java b/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java new file mode 100644 index 00000000..2fafa4a8 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java @@ -0,0 +1,146 @@ +/* + * 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 . + */ + +package com.discordsrv.fabric.command.game; + +import com.discordsrv.common.command.game.abstraction.GameCommandExecutionHelper; +import com.discordsrv.fabric.FabricDiscordSRV; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.ParseResults; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.tree.CommandNode; +import com.mojang.brigadier.tree.RootCommandNode; +import net.minecraft.server.command.ServerCommandSource; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +public class FabricGameCommandExecutionHelper implements GameCommandExecutionHelper { + protected final FabricDiscordSRV discordSRV; + private final CommandDispatcher dispatcher; + + public FabricGameCommandExecutionHelper(FabricDiscordSRV discordSRV) { + this.discordSRV = discordSRV; + this.dispatcher = discordSRV.getServer().getCommandManager().getDispatcher(); + } + + @Override + public CompletableFuture> suggestCommands(List parts) { + String fullCommand = String.join(" ", parts); + if (parts.isEmpty() || fullCommand.isBlank()) { + return getRootCommands(); + } + try { + ParseResults parse = dispatcher.parse(fullCommand, discordSRV.getServer().getCommandSource()); + if (!parse.getExceptions().isEmpty()) { + // There's an error with the command syntax, return the full command and the error message for the user. + List data = new ArrayList<>(); + data.add(fullCommand); + parse.getExceptions().values().stream().map(Exception::getMessage).map(this::splitErrorMessage).forEach(data::addAll); + + return CompletableFuture.completedFuture(data); + } + + if(!parse.getContext().getNodes().isEmpty()) { + CommandNode lastNode = parse.getContext().getNodes().getLast().getNode(); + if (lastNode.getChildren().isEmpty() && lastNode.getRedirect() == null) { + // We reached the end of the command tree. Suggest the full command as a valid command. + return CompletableFuture.completedFuture(Collections.singletonList(fullCommand)); + } + } + + Suggestions suggestions = dispatcher.getCompletionSuggestions(parse).get(); + List data = suggestions.getList().stream() + .map(suggestion -> fullCommand.substring(0, suggestion.getRange().getStart()) + suggestion.getText()) + .collect(Collectors.toList()); + if(data.isEmpty()) { + // Suggestions are empty, Likely the user is still typing an argument. + // If the context is empty, We search all commands from the root. + CommandNode lastNode = !parse.getContext().getNodes().isEmpty() ? parse.getContext().getNodes().getLast().getNode() : parse.getContext().getRootNode(); + + for (CommandNode child : lastNode.getChildren()) { + if (child.getName().toLowerCase().startsWith(parts.getLast().toLowerCase())) { + if(lastNode instanceof RootCommandNode) { + data.add(child.getName()); + continue; + } + + String commandWithoutLastPart = fullCommand.substring(0, fullCommand.length() - parts.getLast().length()); + data.add(commandWithoutLastPart + child.getName()); + } + } + } + return CompletableFuture.completedFuture(data); + } catch (InterruptedException | ExecutionException e) { + return CompletableFuture.completedFuture(Collections.emptyList()); + } + } + + @Override + public List getAliases(String command) { + return Collections.emptyList(); + } + + @Override + public boolean isSameCommand(String command1, String command2) { + CommandNode commandNode1 = dispatcher.findNode(Collections.singleton(command1)); + CommandNode commandNode2 = dispatcher.findNode(Collections.singleton(command2)); + if (commandNode1 != null && commandNode2 != null) { + return commandNode1.equals(commandNode2); + } + return false; + } + + private CompletableFuture> getRootCommands() { + return CompletableFuture.completedFuture(dispatcher.getRoot().getChildren().stream().map(CommandNode::getName).collect(Collectors.toList())); + } + + // Split the error message if it's too long on a period or a comma. If the message reached 97 characters, split at that point and continue. + private List splitErrorMessage(String message) { + List parts = new ArrayList<>(); + int start = 0; + + while (start < message.length()) { + // Maximum line length (100 - 7 for "Error: " = 93) + int end = Math.min(start + 93, message.length()); + String chunk = message.substring(start, end); + + int splitIndex = Math.max(chunk.lastIndexOf('.'), chunk.lastIndexOf(',')); + if (splitIndex != -1 && start + splitIndex < end) { + parts.add("Error: " + message.substring(start, start + splitIndex + 1)); + start += splitIndex + 1; + } else { + // Split at 90 characters (leaving room for "Error: " and "...") + if (end < message.length()) { + parts.add("Error: " + message.substring(start, start + 90) + "..."); + start += 90; + } else { + parts.add("Error: " + message.substring(start)); + break; + } + } + } + + return parts; + } + +} From 90d89ade8a5966c426b9f78998c8c55e712ac0b4 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Fri, 17 Jan 2025 08:46:10 +0300 Subject: [PATCH 38/51] Final build script changes --- buildscript/final.gradle | 6 ++++-- buildscript/relocations.gradle | 2 -- bungee/loader/build.gradle | 8 ++++++++ fabric/build.gradle | 6 +++--- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/buildscript/final.gradle b/buildscript/final.gradle index c7fe364f..faae721e 100644 --- a/buildscript/final.gradle +++ b/buildscript/final.gradle @@ -1,6 +1,6 @@ // Buildscript for loaders & standalone platforms -task copyOutput(type: Copy) { +tasks.register('copyOutput', Copy) { from(this.shadowJar) into rootProject.file('jars') } @@ -14,5 +14,7 @@ shadowJar { rename { fileName -> 'LICENSE.txt' } } - finalizedBy copyOutput + if (it.project.name != "fabric") { + finalizedBy copyOutput + } } diff --git a/buildscript/relocations.gradle b/buildscript/relocations.gradle index 58be7b2f..ed052d9c 100644 --- a/buildscript/relocations.gradle +++ b/buildscript/relocations.gradle @@ -42,8 +42,6 @@ 'net.kyori.adventure.ansi', 'net.kyori.adventure.examination', 'net.kyori.adventure.option', -// 'net.kyori.adventure.platform', -// 'net.kyori.adventure.text.serializer', // EnhancedLegacyText, MCDiscordReserializer 'dev.vankka.enhancedlegacytext', diff --git a/bungee/loader/build.gradle b/bungee/loader/build.gradle index 72f85bbf..2e82f832 100644 --- a/bungee/loader/build.gradle +++ b/bungee/loader/build.gradle @@ -1,5 +1,13 @@ import org.apache.tools.ant.filters.ReplaceTokens +[ + 'net.kyori.adventure.platform', + 'net.kyori.adventure.text.serializer' +].each { + tasks.shadowJar.relocate it, 'com.discordsrv.dependencies.' + it + tasks.generateRuntimeDownloadResourceForRuntimeDownloadOnly.relocate it, 'com.discordsrv.dependencies.' + it +} + apply plugin: 'xyz.jpenilla.run-waterfall' apply from: rootProject.file('buildscript/loader.gradle') diff --git a/fabric/build.gradle b/fabric/build.gradle index f9f33e74..46d3e272 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -1,7 +1,7 @@ apply from: rootProject.file('buildscript/standalone.gradle') apply plugin: 'fabric-loom' -configurations.all { +configurations.configureEach { resolutionStrategy { force "org.slf4j:slf4j-api:1.7.36" // Introduced by Minecraft itself } @@ -24,7 +24,7 @@ shadowJar { mergeServiceFiles() } -copyOutput { +tasks.register('copyRemappedJar', Copy) { from remapJar.archiveFile into rootProject.file('jars') } @@ -36,7 +36,7 @@ remapJar { archiveBaseName = 'DiscordSRV-Fabric' archiveClassifier = jar.archiveClassifier - finalizedBy copyOutput // TODO: This currently adds the remapped jar to the jars folder with the shadow jar. The fix for the buildable jar was the artifacts task. + finalizedBy copyRemappedJar } artifacts { From 58d81a7c73cf4ea0ef61f88b736ba51548e9ff00 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Fri, 17 Jan 2025 10:14:15 +0300 Subject: [PATCH 39/51] Command feedback --- .../fabric/console/FabricConsole.java | 10 ++- .../executor/FabricCommandExecutor.java | 4 +- .../FabricCommandFeedbackExecutor.java | 75 +++++++++++++++++++ 3 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandFeedbackExecutor.java diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java b/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java index 9b8095f1..d22b5e81 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java +++ b/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java @@ -25,6 +25,12 @@ import com.discordsrv.common.core.logging.backend.impl.Log4JLoggerImpl; import com.discordsrv.common.feature.console.Console; import com.discordsrv.fabric.console.executor.FabricCommandExecutor; +import com.discordsrv.fabric.console.executor.FabricCommandFeedbackExecutor; +import net.kyori.adventure.text.Component; +import net.minecraft.server.command.ServerCommandSource; + +import java.util.function.Consumer; +import java.util.function.Function; public class FabricConsole extends FabricCommandSender implements Console { @@ -34,7 +40,9 @@ public class FabricConsole extends FabricCommandSender implements Console { public FabricConsole(FabricDiscordSRV discordSRV) { super(discordSRV, discordSRV.getServer().getCommandSource()); this.loggingBackend = Log4JLoggerImpl.getRoot(); - this.executorProvider = consumer -> new FabricCommandExecutor(discordSRV); + + Function, ServerCommandSource> commandSenderProvider = consumer -> new FabricCommandFeedbackExecutor(discordSRV.getServer(), consumer).getCommandSource(); + this.executorProvider = consumer -> new FabricCommandExecutor(discordSRV, commandSenderProvider.apply(consumer)); } @Override diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java index 0d986698..7ff45ca6 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java +++ b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java @@ -27,9 +27,9 @@ public class FabricCommandExecutor implements CommandExecutor { private final FabricDiscordSRV discordSRV; private final ServerCommandSource source; - public FabricCommandExecutor(FabricDiscordSRV discordSRV) { + public FabricCommandExecutor(FabricDiscordSRV discordSRV, ServerCommandSource source) { this.discordSRV = discordSRV; - this.source = discordSRV.getServer().getCommandSource(); + this.source = source; } @Override diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandFeedbackExecutor.java b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandFeedbackExecutor.java new file mode 100644 index 00000000..e6acc973 --- /dev/null +++ b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandFeedbackExecutor.java @@ -0,0 +1,75 @@ +/* + * 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 . + */ + +package com.discordsrv.fabric.console.executor; + +import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; +import net.kyori.adventure.text.Component; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.CommandOutput; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.math.Vec2f; +import net.minecraft.util.math.Vec3d; + +import java.util.function.Consumer; + +public class FabricCommandFeedbackExecutor implements CommandOutput, Consumer { + + private final MinecraftServer server; + private final Consumer componentConsumer; + + public FabricCommandFeedbackExecutor(MinecraftServer server, Consumer componentConsumer) { + this.server = server; + this.componentConsumer = componentConsumer; + } + + public ServerCommandSource getCommandSource() { + ServerWorld serverWorld = server.getOverworld(); + return new ServerCommandSource( + this, serverWorld == null ? Vec3d.ZERO : Vec3d.of(serverWorld.getSpawnPos()), Vec2f.ZERO, serverWorld, 4, "DiscordSRV", Text.literal("DiscordSRV"), server, null + ); + } + + @Override + public void sendMessage(Text message) { + accept(Component.text(Formatting.strip(message.getString()))); + } + + @Override + public void accept(Component component) { + componentConsumer.accept(component); + } + + @Override + public boolean shouldReceiveFeedback() { + return true; + } + + @Override + public boolean shouldTrackOutput() { + return true; + } + + @Override + public boolean shouldBroadcastConsoleToOps() { + return true; + } +} From f4dcb91afeacca8d954846e756d2ff3b3d4aac28 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Fri, 17 Jan 2025 10:19:38 +0300 Subject: [PATCH 40/51] Fix issue with trailing space --- .../fabric/command/game/FabricGameCommandExecutionHelper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java b/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java index 2fafa4a8..4aeaa5f2 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java +++ b/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java @@ -89,6 +89,7 @@ public CompletableFuture> suggestCommands(List parts) { } } } + data = data.stream().map(String::trim).distinct().collect(Collectors.toList()); return CompletableFuture.completedFuture(data); } catch (InterruptedException | ExecutionException e) { return CompletableFuture.completedFuture(Collections.emptyList()); From 7757629d70acaef873d61237c6ddba704195da90 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Sun, 19 Jan 2025 18:06:49 +0300 Subject: [PATCH 41/51] Squashing a few bugs in ban sync --- .../fabric/module/ban/FabricBanModule.java | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java index 50f77123..c868fe45 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java @@ -26,10 +26,13 @@ import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.fabric.module.AbstractFabricModule; import com.mojang.authlib.GameProfile; +import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; import net.minecraft.server.BannedPlayerEntry; import net.minecraft.server.BannedPlayerList; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; +import net.minecraft.util.UserCache; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -61,7 +64,9 @@ public static void onBan(GameProfile gameProfile) { BanSyncModule module = discordSRV.getModule(BanSyncModule.class); if (module != null) { instance.getBan(gameProfile.getId()) - .whenComplete((punishment, t) -> module.notifyBanned(Objects.requireNonNull(discordSRV.playerProvider().player(gameProfile.getId())), punishment)); + .whenComplete((punishment, t) -> { + if (punishment != null) module.notifyBanned(Objects.requireNonNull(discordSRV.playerProvider().player(gameProfile.getId())), punishment); + }); } } @@ -102,17 +107,23 @@ public CompletableFuture addBan( @NotNull MinecraftComponent punisher ) { try { - discordSRV.getServer().getPlayerManager().getUserBanList().add(new BannedPlayerEntry( - discordSRV.getServer().getUserCache().getByUuid(playerUUID).get(), - null, - ComponentUtil.fromAPI(reason).toString(), - null, - ComponentUtil.fromAPI(punisher).toString() - )); - - ServerPlayerEntity serverPlayerEntity = discordSRV.getServer().getPlayerManager().getPlayer(playerUUID); + MinecraftServer server = discordSRV.getServer(); + UserCache userCache = server.getUserCache(); + + GameProfile gameProfile = null; + if (userCache != null) { + gameProfile = userCache.getByUuid(playerUUID).orElse(null); + } + + String reasonProvided = reason != null ? reason.asPlainString() : null; + Date expiration = until != null ? Date.from(until) : null; + + BannedPlayerEntry banEntry = new BannedPlayerEntry(gameProfile, new Date(), reasonProvided, expiration, punisher.asPlainString()); + server.getPlayerManager().getUserBanList().add(banEntry); + + ServerPlayerEntity serverPlayerEntity = server.getPlayerManager().getPlayer(playerUUID); if (serverPlayerEntity != null) { - serverPlayerEntity.networkHandler.disconnect(Text.translatable("multiplayer.disconnect.banned")); + serverPlayerEntity.networkHandler.disconnect(reason != null ? MinecraftServerAudiences.of(server).asNative(reason.asAdventure()) : Text.translatable("multiplayer.disconnect.banned")); } } catch (Exception e) { discordSRV.logger().error("Failed to ban player", e); From 4ce33208c5df1f2b80e681379249c5ac1944f4e1 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 20 Jan 2025 09:00:02 +0300 Subject: [PATCH 42/51] Buildscript changes --- bukkit/build.gradle | 2 ++ bungee/build.gradle | 4 +++- bungee/loader/build.gradle | 8 -------- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/bukkit/build.gradle b/bukkit/build.gradle index 9e9b0a9e..1701a15c 100644 --- a/bukkit/build.gradle +++ b/bukkit/build.gradle @@ -6,6 +6,8 @@ allprojects { [ 'net.kyori', + 'net.kyori.adventure.platform', + 'net.kyori.adventure.text.serializer', 'me.lucko.commodore' ].each { tasks.shadowJar.relocate it, 'com.discordsrv.dependencies.' + it diff --git a/bungee/build.gradle b/bungee/build.gradle index 9eb3954a..84bae6ab 100644 --- a/bungee/build.gradle +++ b/bungee/build.gradle @@ -3,7 +3,9 @@ shadowJar { configure { [ - 'net.kyori' + 'net.kyori', + 'net.kyori.adventure.platform', + 'net.kyori.adventure.text.serializer' ].each { relocate it, 'com.discordsrv.dependencies.' + it } diff --git a/bungee/loader/build.gradle b/bungee/loader/build.gradle index 2e82f832..72f85bbf 100644 --- a/bungee/loader/build.gradle +++ b/bungee/loader/build.gradle @@ -1,13 +1,5 @@ import org.apache.tools.ant.filters.ReplaceTokens -[ - 'net.kyori.adventure.platform', - 'net.kyori.adventure.text.serializer' -].each { - tasks.shadowJar.relocate it, 'com.discordsrv.dependencies.' + it - tasks.generateRuntimeDownloadResourceForRuntimeDownloadOnly.relocate it, 'com.discordsrv.dependencies.' + it -} - apply plugin: 'xyz.jpenilla.run-waterfall' apply from: rootProject.file('buildscript/loader.gradle') From e51d04ad978712bd3155ad6bc6b6751cb326c7e1 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 20 Jan 2025 09:31:02 +0300 Subject: [PATCH 43/51] Make startup faster --- .../java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java | 4 +++- .../com/discordsrv/fabric/player/FabricPlayerProvider.java | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java index 6e487941..78edb3f5 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java +++ b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java @@ -64,12 +64,14 @@ public DiscordSRVFabricBootstrap() { @Override public void onInitializeServer() { - ServerLifecycleEvents.SERVER_STARTED.register(minecraftServer -> { + ServerLifecycleEvents.SERVER_STARTING.register(minecraftServer -> { this.minecraftServer = minecraftServer; lifecycleManager.loadAndEnable(() -> this.discordSRV = new FabricDiscordSRV(this)); this.discordSRV.runServerStarted(); }); + ServerLifecycleEvents.SERVER_STARTED.register(minecraftServer -> this.discordSRV.runServerStarted()); + ServerLifecycleEvents.SERVER_STOPPING.register(minecraftServer -> { if(this.discordSRV != null) this.discordSRV.runDisable(); }); diff --git a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java index eda33879..4ab76df5 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java +++ b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java @@ -26,8 +26,6 @@ import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; -import java.util.UUID; - public class FabricPlayerProvider extends AbstractPlayerProvider { private boolean enabled = false; @@ -41,6 +39,7 @@ public FabricPlayerProvider(FabricDiscordSRV discordSRV) { @Override public void subscribe() { enabled = true; + if (discordSRV.getServer() == null || discordSRV.getServer().getPlayerManager() == null) return; // Server not started yet, So there's no players to add // Add players that are already connected for (ServerPlayerEntity player : discordSRV.getServer().getPlayerManager().getPlayerList()) { From c675504addce6862e11c0f7af0ec89707b81536f Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 20 Jan 2025 09:53:05 +0300 Subject: [PATCH 44/51] Implement suggestions + Create a single MinecraftServerAudiences instance --- .../com/discordsrv/fabric/DiscordSRVFabricBootstrap.java | 9 ++++++++- .../java/com/discordsrv/fabric/FabricDiscordSRV.java | 6 ++++++ .../fabric/command/game/sender/FabricCommandSender.java | 3 +-- .../console/executor/FabricCommandFeedbackExecutor.java | 1 - .../discordsrv/fabric/module/ban/FabricBanModule.java | 3 +-- .../fabric/module/chat/FabricAdvancementModule.java | 4 +--- .../discordsrv/fabric/module/chat/FabricChatModule.java | 5 +---- .../discordsrv/fabric/module/chat/FabricDeathModule.java | 3 +-- .../discordsrv/fabric/module/chat/FabricJoinModule.java | 3 +-- .../discordsrv/fabric/module/chat/FabricQuitModule.java | 2 +- .../requiredlinking/FabricRequiredLinkingModule.java | 4 ++-- 11 files changed, 23 insertions(+), 20 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java index 78edb3f5..f6f0bd6f 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java +++ b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java @@ -27,6 +27,7 @@ import net.fabricmc.api.DedicatedServerModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; +import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; import net.minecraft.GameVersion; import net.minecraft.MinecraftVersion; import net.minecraft.server.MinecraftServer; @@ -44,6 +45,7 @@ public class DiscordSRVFabricBootstrap implements DedicatedServerModInitializer, private MinecraftServer minecraftServer; private final Path dataDirectory; private FabricDiscordSRV discordSRV; + private MinecraftServerAudiences adventure; public DiscordSRVFabricBootstrap() { this.logger = new Log4JLoggerImpl(LogManager.getLogger("DiscordSRV")); @@ -60,14 +62,15 @@ public DiscordSRVFabricBootstrap() { throw new RuntimeException(e); } this.minecraftServer = null; + this.adventure = null; } @Override public void onInitializeServer() { ServerLifecycleEvents.SERVER_STARTING.register(minecraftServer -> { this.minecraftServer = minecraftServer; + this.adventure = MinecraftServerAudiences.of(minecraftServer); lifecycleManager.loadAndEnable(() -> this.discordSRV = new FabricDiscordSRV(this)); - this.discordSRV.runServerStarted(); }); ServerLifecycleEvents.SERVER_STARTED.register(minecraftServer -> this.discordSRV.runServerStarted()); @@ -115,4 +118,8 @@ public MinecraftServer getServer() { public FabricDiscordSRV getDiscordSRV() { return discordSRV; } + + public MinecraftServerAudiences getAdventure() { + return adventure; + } } diff --git a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java index af3666a4..3a9ecf27 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java +++ b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java @@ -40,6 +40,7 @@ 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.kyori.adventure.platform.modcommon.MinecraftServerAudiences; import net.minecraft.server.MinecraftServer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -119,6 +120,11 @@ public MinecraftServer getServer() { return bootstrap.getServer(); } + @NotNull + public MinecraftServerAudiences getAdventure() { + return bootstrap.getAdventure(); + } + @Override public ServerType serverType() { return ServerType.SERVER; diff --git a/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java b/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java index a9fae298..39dcad44 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java +++ b/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java @@ -22,7 +22,6 @@ 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; @@ -48,6 +47,6 @@ public void runCommand(String command) { @Override public @NotNull Audience audience() { - return MinecraftServerAudiences.of(discordSRV.getServer()).audience(commandSource); + return discordSRV.getAdventure().audience(commandSource); } } diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandFeedbackExecutor.java b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandFeedbackExecutor.java index e6acc973..b7602acb 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandFeedbackExecutor.java +++ b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandFeedbackExecutor.java @@ -18,7 +18,6 @@ package com.discordsrv.fabric.console.executor; -import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; import net.kyori.adventure.text.Component; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.CommandOutput; diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java index c868fe45..9569af2a 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java @@ -26,7 +26,6 @@ import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.fabric.module.AbstractFabricModule; import com.mojang.authlib.GameProfile; -import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; import net.minecraft.server.BannedPlayerEntry; import net.minecraft.server.BannedPlayerList; import net.minecraft.server.MinecraftServer; @@ -123,7 +122,7 @@ public CompletableFuture addBan( ServerPlayerEntity serverPlayerEntity = server.getPlayerManager().getPlayer(playerUUID); if (serverPlayerEntity != null) { - serverPlayerEntity.networkHandler.disconnect(reason != null ? MinecraftServerAudiences.of(server).asNative(reason.asAdventure()) : Text.translatable("multiplayer.disconnect.banned")); + serverPlayerEntity.networkHandler.disconnect(reason != null ? discordSRV.getAdventure().asNative(reason.asAdventure()) : Text.translatable("multiplayer.disconnect.banned")); } } catch (Exception e) { discordSRV.logger().error("Failed to ban player", e); diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java index 8635ba0a..37a39433 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java @@ -27,7 +27,6 @@ import net.minecraft.advancement.Advancement; import net.minecraft.advancement.AdvancementEntry; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.Formatting; public class FabricAdvancementModule extends AbstractFabricModule { private final FabricDiscordSRV discordSRV; @@ -45,8 +44,7 @@ public static void onGrant(AdvancementEntry advancementEntry, ServerPlayerEntity FabricDiscordSRV discordSRV = instance.discordSRV; Advancement advancement = advancementEntry.value(); if(advancement.display().isEmpty() || advancement.name().isEmpty()) return; // Usually a crafting recipe. - String title = Formatting.strip(advancement.display().get().getTitle().getString()); - MinecraftComponent advancementTitle = ComponentUtil.fromPlain(title); + MinecraftComponent advancementTitle = ComponentUtil.toAPI(discordSRV.getAdventure().asAdventure(advancement.display().get().getTitle())); // TODO: Add description to the event. So we can explain how the player got the advancement. // String description = Formatting.strip(advancement.display().get().getDescription().getString()); diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java index 693d8dbb..642879d0 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java @@ -24,13 +24,10 @@ import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.fabric.module.AbstractFabricModule; import net.fabricmc.fabric.api.message.v1.ServerMessageEvents; -import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; import net.minecraft.network.message.MessageType; import net.minecraft.network.message.SignedMessage; import net.minecraft.server.network.ServerPlayerEntity; -import java.util.Objects; - public class FabricChatModule extends AbstractFabricModule { private final FabricDiscordSRV discordSRV; @@ -49,7 +46,7 @@ private void onChatMessage(SignedMessage signedMessage, ServerPlayerEntity serve discordSRV.eventBus().publish(new GameChatMessageReceiveEvent( null, discordSRV.playerProvider().player(serverPlayerEntity), - ComponentUtil.fromPlain(MinecraftServerAudiences.of(serverPlayerEntity.server).asAdventure(signedMessage).message()), + ComponentUtil.toAPI(discordSRV.getAdventure().asAdventure(signedMessage.getContent())), new GlobalChannel(discordSRV), false )); diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java index 7d294c0b..25e7c795 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java @@ -29,7 +29,6 @@ import net.minecraft.entity.damage.DamageSource; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; -import net.minecraft.util.Formatting; public class FabricDeathModule extends AbstractFabricModule { private final FabricDiscordSRV discordSRV; @@ -47,7 +46,7 @@ private void onDeath(LivingEntity livingEntity, DamageSource damageSource) { if (!enabled) return; if(livingEntity instanceof ServerPlayerEntity) { Text message = damageSource.getDeathMessage(livingEntity); - MinecraftComponent minecraftComponent = ComponentUtil.fromPlain(Formatting.strip(message.getString())); + MinecraftComponent minecraftComponent = ComponentUtil.toAPI(discordSRV.getAdventure().asAdventure(message)); DiscordSRVPlayer player = discordSRV.playerProvider().player((ServerPlayerEntity) livingEntity); discordSRV.eventBus().publish( diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java index 31fd98a9..878d97b2 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java @@ -31,7 +31,6 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.MutableText; import net.minecraft.text.Text; -import net.minecraft.util.Formatting; import java.util.Objects; @@ -75,6 +74,6 @@ private MinecraftComponent getJoinMessage(ServerPlayerEntity playerEntity) { mutableText = Text.translatable("multiplayer.player.joined.renamed", playerEntity.getDisplayName(), playerEntity.getName()); } - return ComponentUtil.fromPlain(Formatting.strip(mutableText.formatted(Formatting.YELLOW).getString())); + return ComponentUtil.toAPI(discordSRV.getAdventure().asAdventure(mutableText)); } } diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java index bc76fe6c..bb184057 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java @@ -63,6 +63,6 @@ private void onDisconnect(ServerPlayNetworkHandler serverPlayNetworkHandler, Min public MinecraftComponent getQuitMessage(ServerPlayerEntity player) { Text message = Text.translatable("multiplayer.player.left", player.getDisplayName()).formatted(Formatting.YELLOW); - return ComponentUtil.fromPlain(Formatting.strip(message.getString())); + return ComponentUtil.toAPI(discordSRV.getAdventure().asAdventure(message)); } } diff --git a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java index bad76fa2..da969657 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java @@ -32,7 +32,6 @@ import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; -import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; import net.kyori.adventure.text.Component; import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; import net.minecraft.server.MinecraftServer; @@ -137,6 +136,7 @@ public static Text checkCanJoin(GameProfile profile) { if (!instance.enabled) return null; FabricDiscordSRV discordSRV = instance.discordSRV; + assert discordSRV != null; ServerRequiredLinkingConfig config = instance.config(); if (!config.enabled || config.action != ServerRequiredLinkingConfig.Action.KICK) { return null; @@ -147,7 +147,7 @@ public static Text checkCanJoin(GameProfile profile) { Component kickReason = instance.getBlockReason(playerUUID, playerName, true).join(); if (kickReason != null) { - return MinecraftServerAudiences.of(discordSRV.getServer()).asNative(kickReason); + return discordSRV.getAdventure().asNative(kickReason); } return null; From 69a4aeed4af488de07e3a4b51bf1456316663ca1 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 20 Jan 2025 09:53:47 +0300 Subject: [PATCH 45/51] Fix bug if player spawns at exactly .5 in x or z --- .../fabric/requiredlinking/FabricRequiredLinkingModule.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java index da969657..d8448c92 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java @@ -41,6 +41,7 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -235,7 +236,7 @@ public static void onPlayerMove(ServerPlayerEntity player, PlayerMoveC2SPacket p } BlockPos from = player.getBlockPos(); - BlockPos to = new BlockPos((int) packet.getX(player.getX()), (int) packet.getY(player.getY()), (int) packet.getZ(player.getZ())); + BlockPos to = new BlockPos(MathHelper.floor(packet.getX(player.getX())), MathHelper.floor(packet.getY(player.getY())), MathHelper.floor(packet.getZ(player.getZ()))); if(from.getX() == to.getX() && from.getY() >= to.getY() && from.getZ() == to.getZ()) { return; } From ccf301b3e154d9faa7a58283d5f9881d31df06ea Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 20 Jan 2025 10:08:14 +0300 Subject: [PATCH 46/51] When reloading config and making linking not required. The player can't send messages. --- .../requiredlinking/FabricRequiredLinkingModule.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java index d8448c92..86ea0f72 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java @@ -162,7 +162,12 @@ public static Text checkCanJoin(GameProfile profile) { private final List loginsHandled = new CopyOnWriteArrayList<>(); private boolean isFrozen(ServerPlayerEntity player) { - return frozen.containsKey(player.getUuid()); + Component freezeReason = frozen.get(player.getUuid()); + if (freezeReason == null) { + frozen.remove(player.getUuid()); + return false; + } + return true; } private void freeze(IPlayer player, Component blockReason) { From 15a537fb99a787ee891fcd5958965e29837d2df3 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Mon, 20 Jan 2025 11:09:50 +0300 Subject: [PATCH 47/51] Make allowChatMessage a method instead of a lambda --- .../FabricRequiredLinkingModule.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java index 86ea0f72..7349688a 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java @@ -33,6 +33,8 @@ import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.kyori.adventure.text.Component; +import net.minecraft.network.message.MessageType; +import net.minecraft.network.message.SignedMessage; import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.command.ServerCommandSource; @@ -82,15 +84,7 @@ public void enable() { } public void register() { - ServerMessageEvents.ALLOW_CHAT_MESSAGE.register((text, player, parameters) -> { - // True if the message should be sent - if (isFrozen(player)) { - player.sendMessage(frozen.get(player.getUuid())); - return false; - } - return true; - }); - + ServerMessageEvents.ALLOW_CHAT_MESSAGE.register(this::allowChatMessage); ServerConfigurationConnectionEvents.CONFIGURE.register(this::onPlayerPreLogin); ServerPlayConnectionEvents.JOIN.register(this::onPlayerJoin); ServerPlayConnectionEvents.DISCONNECT.register(this::onPlayerQuit); @@ -175,6 +169,18 @@ private void freeze(IPlayer player, Component blockReason) { player.sendMessage(blockReason); } + private boolean allowChatMessage(SignedMessage signedMessage, ServerPlayerEntity player, MessageType.Parameters parameters) { + // True if the message should be sent + Component freezeReason = instance.frozen.get(player.getUuid()); + if (freezeReason == null) { + return true; + } + + IPlayer iPlayer = instance.discordSRV.playerProvider().player(player); + iPlayer.sendMessage(freezeReason); + return false; + } + private void onPlayerPreLogin(ServerConfigurationNetworkHandler handler, MinecraftServer minecraftServer) { if(!enabled) return; UUID playerUUID = handler.getDebugProfile().getId(); From 13784a1fc0851d967fed2781bb405be441f3aa4f Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Tue, 21 Jan 2025 11:20:41 +0300 Subject: [PATCH 48/51] Remove unused access wideners --- fabric/src/main/resources/discordsrv.accesswidener | 6 ------ 1 file changed, 6 deletions(-) diff --git a/fabric/src/main/resources/discordsrv.accesswidener b/fabric/src/main/resources/discordsrv.accesswidener index 1fc22989..3fde5170 100644 --- a/fabric/src/main/resources/discordsrv.accesswidener +++ b/fabric/src/main/resources/discordsrv.accesswidener @@ -1,7 +1 @@ accessWidener v1 named -accessible method net/minecraft/server/network/ServerPlayNetworkHandler clampHorizontal (D)D -accessible method net/minecraft/server/network/ServerPlayNetworkHandler clampVertical (D)D - -accessible field net/minecraft/server/network/ServerPlayNetworkHandler lastTickX D -accessible field net/minecraft/server/network/ServerPlayNetworkHandler lastTickY D -accessible field net/minecraft/server/network/ServerPlayNetworkHandler lastTickZ D \ No newline at end of file From 87e5e32a54dc3bad5c419d0a4a052b26ec5d27b4 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Tue, 21 Jan 2025 11:31:27 +0300 Subject: [PATCH 49/51] Optimize imports and clean up code Signed-off-by: IxPrumxI --- .../fabric/DiscordSRVFabricBootstrap.java | 4 +- .../discordsrv/fabric/FabricDiscordSRV.java | 26 +-- .../FabricGameCommandExecutionHelper.java | 6 +- .../game/handler/FabricCommandHandler.java | 2 +- .../game/sender/FabricCommandSender.java | 2 +- .../fabric/config/main/FabricConfig.java | 6 +- .../fabric/console/FabricConsole.java | 4 +- .../executor/FabricCommandExecutor.java | 2 +- .../fabric/mixin/ban/PardonCommandMixin.java | 1 - .../ServerPlayNetworkHandlerMixin.java | 2 +- .../fabric/module/AbstractFabricModule.java | 3 +- .../fabric/module/ban/FabricBanModule.java | 14 +- .../module/chat/FabricAdvancementModule.java | 6 +- .../fabric/module/chat/FabricChatModule.java | 10 +- .../fabric/module/chat/FabricDeathModule.java | 2 +- .../fabric/player/FabricPlayer.java | 4 +- .../fabric/player/FabricPlayerProvider.java | 9 +- .../fabric/plugin/FabricModManager.java | 7 - .../FabricRequiredLinkingModule.java | 209 +++++++++--------- 19 files changed, 154 insertions(+), 165 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java index f6f0bd6f..437e9fa5 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java +++ b/fabric/src/main/java/com/discordsrv/fabric/DiscordSRVFabricBootstrap.java @@ -42,8 +42,8 @@ public class DiscordSRVFabricBootstrap implements DedicatedServerModInitializer, private final Logger logger; private final ClasspathAppender classpathAppender; private final LifecycleManager lifecycleManager; - private MinecraftServer minecraftServer; private final Path dataDirectory; + private MinecraftServer minecraftServer; private FabricDiscordSRV discordSRV; private MinecraftServerAudiences adventure; @@ -76,7 +76,7 @@ public void onInitializeServer() { ServerLifecycleEvents.SERVER_STARTED.register(minecraftServer -> this.discordSRV.runServerStarted()); ServerLifecycleEvents.SERVER_STOPPING.register(minecraftServer -> { - if(this.discordSRV != null) this.discordSRV.runDisable(); + if (this.discordSRV != null) this.discordSRV.runDisable(); }); } diff --git a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java index 3a9ecf27..a304d76c 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java +++ b/fabric/src/main/java/com/discordsrv/fabric/FabricDiscordSRV.java @@ -18,34 +18,36 @@ package com.discordsrv.fabric; +import com.discordsrv.common.AbstractDiscordSRV; +import com.discordsrv.common.abstraction.plugin.PluginManager; import com.discordsrv.common.command.game.abstraction.GameCommandExecutionHelper; +import com.discordsrv.common.command.game.abstraction.handler.ICommandHandler; 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.configurate.manager.abstraction.ServerConfigManager; import com.discordsrv.common.config.connection.ConnectionConfig; import com.discordsrv.common.config.messages.MessagesConfig; +import com.discordsrv.common.core.scheduler.StandardScheduler; +import com.discordsrv.common.feature.debug.data.OnlineMode; import com.discordsrv.common.feature.messageforwarding.game.MinecraftToDiscordChatModule; import com.discordsrv.fabric.command.game.FabricGameCommandExecutionHelper; +import com.discordsrv.fabric.command.game.handler.FabricCommandHandler; import com.discordsrv.fabric.config.main.FabricConfig; import com.discordsrv.fabric.console.FabricConsole; -import com.discordsrv.fabric.command.game.handler.FabricCommandHandler; -import com.discordsrv.fabric.module.chat.*; import com.discordsrv.fabric.module.ban.FabricBanModule; -import com.discordsrv.fabric.requiredlinking.FabricRequiredLinkingModule; +import com.discordsrv.fabric.module.chat.*; 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 com.discordsrv.fabric.requiredlinking.FabricRequiredLinkingModule; import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences; import net.minecraft.server.MinecraftServer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.net.*; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; import java.security.CodeSource; import java.util.jar.JarFile; @@ -69,7 +71,7 @@ public FabricDiscordSRV(DiscordSRVFabricBootstrap bootstrap) { this.scheduler = new StandardScheduler(this); this.console = new FabricConsole(this); this.playerProvider = new FabricPlayerProvider(this); - this.modManager = new FabricModManager(this); + this.modManager = new FabricModManager(); this.commandHandler = new FabricCommandHandler(this); this.executionHelper = new FabricGameCommandExecutionHelper(this); @@ -112,10 +114,6 @@ protected URL getManifest() { } } - public FabricModManager getModManager() { - return modManager; - } - public MinecraftServer getServer() { return bootstrap.getServer(); } diff --git a/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java b/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java index 4aeaa5f2..b3fddd41 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java +++ b/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java @@ -60,7 +60,7 @@ public CompletableFuture> suggestCommands(List parts) { return CompletableFuture.completedFuture(data); } - if(!parse.getContext().getNodes().isEmpty()) { + if (!parse.getContext().getNodes().isEmpty()) { CommandNode lastNode = parse.getContext().getNodes().getLast().getNode(); if (lastNode.getChildren().isEmpty() && lastNode.getRedirect() == null) { // We reached the end of the command tree. Suggest the full command as a valid command. @@ -72,14 +72,14 @@ public CompletableFuture> suggestCommands(List parts) { List data = suggestions.getList().stream() .map(suggestion -> fullCommand.substring(0, suggestion.getRange().getStart()) + suggestion.getText()) .collect(Collectors.toList()); - if(data.isEmpty()) { + if (data.isEmpty()) { // Suggestions are empty, Likely the user is still typing an argument. // If the context is empty, We search all commands from the root. CommandNode lastNode = !parse.getContext().getNodes().isEmpty() ? parse.getContext().getNodes().getLast().getNode() : parse.getContext().getRootNode(); for (CommandNode child : lastNode.getChildren()) { if (child.getName().toLowerCase().startsWith(parts.getLast().toLowerCase())) { - if(lastNode instanceof RootCommandNode) { + if (lastNode instanceof RootCommandNode) { data.add(child.getName()); continue; } diff --git a/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java b/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java index d183f6c4..305b8de9 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java +++ b/fabric/src/main/java/com/discordsrv/fabric/command/game/handler/FabricCommandHandler.java @@ -18,11 +18,11 @@ package com.discordsrv.fabric.command.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.discordsrv.fabric.FabricDiscordSRV; import com.mojang.brigadier.tree.LiteralCommandNode; import net.minecraft.command.CommandSource; import net.minecraft.server.command.ServerCommandSource; diff --git a/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java b/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java index 39dcad44..1ef91d07 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java +++ b/fabric/src/main/java/com/discordsrv/fabric/command/game/sender/FabricCommandSender.java @@ -18,8 +18,8 @@ package com.discordsrv.fabric.command.game.sender; -import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.common.command.game.abstraction.sender.ICommandSender; +import com.discordsrv.fabric.FabricDiscordSRV; import me.lucko.fabric.api.permissions.v0.Permissions; import net.kyori.adventure.audience.Audience; import net.minecraft.server.command.ServerCommandSource; diff --git a/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricConfig.java b/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricConfig.java index 56e06771..c61df1a7 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricConfig.java +++ b/fabric/src/main/java/com/discordsrv/fabric/config/main/FabricConfig.java @@ -30,6 +30,9 @@ @ConfigSerializable public class FabricConfig extends MainConfig { + @Order(5) + public ServerRequiredLinkingConfig requiredLinking = new ServerRequiredLinkingConfig(); + @Override public BaseChannelConfig createDefaultBaseChannel() { return new ServerBaseChannelConfig(); @@ -40,9 +43,6 @@ public BaseChannelConfig createDefaultChannel() { return new ServerChannelConfig(); } - @Order(5) - public ServerRequiredLinkingConfig requiredLinking = new ServerRequiredLinkingConfig(); - @Override public PresenceUpdaterConfig defaultPresenceUpdater() { return new PresenceUpdaterConfig.Server(); diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java b/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java index d22b5e81..529084df 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java +++ b/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java @@ -18,12 +18,12 @@ package com.discordsrv.fabric.console; -import com.discordsrv.fabric.FabricDiscordSRV; -import com.discordsrv.fabric.command.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; +import com.discordsrv.fabric.FabricDiscordSRV; +import com.discordsrv.fabric.command.game.sender.FabricCommandSender; import com.discordsrv.fabric.console.executor.FabricCommandExecutor; import com.discordsrv.fabric.console.executor.FabricCommandFeedbackExecutor; import net.kyori.adventure.text.Component; diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java index 7ff45ca6..def7a667 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java +++ b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandExecutor.java @@ -18,8 +18,8 @@ package com.discordsrv.fabric.console.executor; -import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.common.command.game.abstraction.executor.CommandExecutor; +import com.discordsrv.fabric.FabricDiscordSRV; import net.minecraft.server.command.ServerCommandSource; public class FabricCommandExecutor implements CommandExecutor { diff --git a/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/PardonCommandMixin.java b/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/PardonCommandMixin.java index 1ac62b3a..d164a79e 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/PardonCommandMixin.java +++ b/fabric/src/main/java/com/discordsrv/fabric/mixin/ban/PardonCommandMixin.java @@ -22,7 +22,6 @@ import com.llamalad7.mixinextras.sugar.Local; import com.mojang.authlib.GameProfile; import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.dedicated.command.BanCommand; import net.minecraft.server.dedicated.command.PardonCommand; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/ServerPlayNetworkHandlerMixin.java b/fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/ServerPlayNetworkHandlerMixin.java index cd4ae0cd..dd643d22 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/ServerPlayNetworkHandlerMixin.java +++ b/fabric/src/main/java/com/discordsrv/fabric/mixin/requiredlinking/ServerPlayNetworkHandlerMixin.java @@ -36,6 +36,6 @@ public class ServerPlayNetworkHandlerMixin { @Inject(method = "onPlayerMove", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerEntity;getServerWorld()Lnet/minecraft/server/world/ServerWorld;", ordinal = 1), cancellable = true) private void onPlayerMove(PlayerMoveC2SPacket packet, CallbackInfo ci) { - FabricRequiredLinkingModule.onPlayerMove(player, packet, ci); + FabricRequiredLinkingModule.onPlayerMove(player, packet, ci); } } diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java index 14b5525c..05f2c837 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java @@ -39,5 +39,6 @@ public void disable() { enabled = false; } - public void register() {} + public void register() { + } } \ No newline at end of file diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java index 9569af2a..51fc1ef0 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java @@ -51,12 +51,6 @@ public FabricBanModule(FabricDiscordSRV discordSRV) { instance = this; } - - @Override - public void enable() { - this.enabled = true; - } - public static void onBan(GameProfile gameProfile) { if (instance == null) return; FabricDiscordSRV discordSRV = instance.discordSRV; @@ -64,7 +58,8 @@ public static void onBan(GameProfile gameProfile) { if (module != null) { instance.getBan(gameProfile.getId()) .whenComplete((punishment, t) -> { - if (punishment != null) module.notifyBanned(Objects.requireNonNull(discordSRV.playerProvider().player(gameProfile.getId())), punishment); + if (punishment != null) + module.notifyBanned(Objects.requireNonNull(discordSRV.playerProvider().player(gameProfile.getId())), punishment); }); } } @@ -76,6 +71,11 @@ public static void onPardon(GameProfile gameProfile) { if (module != null) instance.removeBan(gameProfile.getId()).complete(null); } + @Override + public void enable() { + this.enabled = true; + } + @Override public CompletableFuture<@Nullable Punishment> getBan(@NotNull UUID playerUUID) { BannedPlayerList banList = discordSRV.getServer().getPlayerManager().getUserBanList(); diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java index 37a39433..bf182eea 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java @@ -29,8 +29,8 @@ import net.minecraft.server.network.ServerPlayerEntity; public class FabricAdvancementModule extends AbstractFabricModule { - private final FabricDiscordSRV discordSRV; private static FabricAdvancementModule instance; + private final FabricDiscordSRV discordSRV; public FabricAdvancementModule(FabricDiscordSRV discordSRV) { super(discordSRV); @@ -43,10 +43,10 @@ public static void onGrant(AdvancementEntry advancementEntry, ServerPlayerEntity FabricDiscordSRV discordSRV = instance.discordSRV; Advancement advancement = advancementEntry.value(); - if(advancement.display().isEmpty() || advancement.name().isEmpty()) return; // Usually a crafting recipe. + if (advancement.display().isEmpty() || advancement.name().isEmpty()) return; // Usually a crafting recipe. MinecraftComponent advancementTitle = ComponentUtil.toAPI(discordSRV.getAdventure().asAdventure(advancement.display().get().getTitle())); - // TODO: Add description to the event. So we can explain how the player got the advancement. + // TODO: Add description to the event. So we can explain how the player got the advancement. // String description = Formatting.strip(advancement.display().get().getDescription().getString()); // MinecraftComponent advancementDescription = ComponentUtil.fromPlain(description); diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java index 642879d0..3c363973 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java @@ -44,11 +44,11 @@ private void onChatMessage(SignedMessage signedMessage, ServerPlayerEntity serve if (!enabled) return; discordSRV.eventBus().publish(new GameChatMessageReceiveEvent( - null, - discordSRV.playerProvider().player(serverPlayerEntity), - ComponentUtil.toAPI(discordSRV.getAdventure().asAdventure(signedMessage.getContent())), - new GlobalChannel(discordSRV), - false + null, + discordSRV.playerProvider().player(serverPlayerEntity), + ComponentUtil.toAPI(discordSRV.getAdventure().asAdventure(signedMessage.getContent())), + new GlobalChannel(discordSRV), + false )); } } diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java index 25e7c795..95c0e84f 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java @@ -44,7 +44,7 @@ public void register() { private void onDeath(LivingEntity livingEntity, DamageSource damageSource) { if (!enabled) return; - if(livingEntity instanceof ServerPlayerEntity) { + if (livingEntity instanceof ServerPlayerEntity) { Text message = damageSource.getDeathMessage(livingEntity); MinecraftComponent minecraftComponent = ComponentUtil.toAPI(discordSRV.getAdventure().asAdventure(message)); diff --git a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java index 4e4c2b45..4960561c 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java +++ b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java @@ -18,11 +18,11 @@ package com.discordsrv.fabric.player; -import com.discordsrv.fabric.FabricDiscordSRV; -import com.discordsrv.fabric.command.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 com.discordsrv.fabric.FabricDiscordSRV; +import com.discordsrv.fabric.command.game.sender.FabricCommandSender; import net.kyori.adventure.identity.Identity; import net.kyori.adventure.text.Component; import net.minecraft.server.network.ServerPlayerEntity; diff --git a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java index 4ab76df5..b7dcff79 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java +++ b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java @@ -18,8 +18,8 @@ package com.discordsrv.fabric.player; -import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.common.abstraction.player.provider.AbstractPlayerProvider; +import com.discordsrv.fabric.FabricDiscordSRV; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.minecraft.server.MinecraftServer; @@ -39,7 +39,8 @@ public FabricPlayerProvider(FabricDiscordSRV discordSRV) { @Override public void subscribe() { enabled = true; - if (discordSRV.getServer() == null || discordSRV.getServer().getPlayerManager() == null) return; // Server not started yet, So there's no players to add + if (discordSRV.getServer() == null || discordSRV.getServer().getPlayerManager() == null) + return; // Server not started yet, So there's no players to add // Add players that are already connected for (ServerPlayerEntity player : discordSRV.getServer().getPlayerManager().getPlayerList()) { @@ -61,12 +62,12 @@ private void onDisconnect(ServerPlayNetworkHandler serverPlayNetworkHandler, Min } private void addPlayer(ServerPlayerEntity player, boolean initial) { - if(!enabled) return; + if (!enabled) return; addPlayer(player.getUuid(), new FabricPlayer(discordSRV, player), initial); } private void removePlayer(ServerPlayerEntity player) { - if(!enabled) return; + if (!enabled) return; removePlayer(player.getUuid()); } diff --git a/fabric/src/main/java/com/discordsrv/fabric/plugin/FabricModManager.java b/fabric/src/main/java/com/discordsrv/fabric/plugin/FabricModManager.java index 3671f8c5..bd5e02a6 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/plugin/FabricModManager.java +++ b/fabric/src/main/java/com/discordsrv/fabric/plugin/FabricModManager.java @@ -18,7 +18,6 @@ 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; @@ -30,12 +29,6 @@ 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)); diff --git a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java index 7349688a..29d1063d 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java @@ -18,12 +18,12 @@ package com.discordsrv.fabric.requiredlinking; -import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.config.main.linking.ServerRequiredLinkingConfig; import com.discordsrv.common.feature.linking.LinkStore; import com.discordsrv.common.feature.linking.requirelinking.ServerRequireLinkingModule; +import com.discordsrv.fabric.FabricDiscordSRV; import com.discordsrv.fabric.player.FabricPlayer; import com.github.benmanes.caffeine.cache.Cache; import com.mojang.authlib.GameProfile; @@ -56,9 +56,10 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule { private static FabricRequiredLinkingModule instance; - - private boolean enabled = false; private final Cache linkCheckRateLimit; + private final Map frozen = new ConcurrentHashMap<>(); + private final List loginsHandled = new CopyOnWriteArrayList<>(); + private boolean enabled = false; public FabricRequiredLinkingModule(FabricDiscordSRV discordSRV) { super(discordSRV); @@ -71,11 +72,102 @@ public FabricRequiredLinkingModule(FabricDiscordSRV discordSRV) { instance = this; } + @Nullable + public static Text checkCanJoin(GameProfile profile) { + if (instance == null || (instance.discordSRV != null && instance.discordSRV.status() != DiscordSRV.Status.CONNECTED)) { + return Text.of("Currently unavailable to check link status because the server is still connecting to Discord.\n\nTry again in a minute."); + } + if (!instance.enabled) return null; + + FabricDiscordSRV discordSRV = instance.discordSRV; + assert discordSRV != null; + ServerRequiredLinkingConfig config = instance.config(); + if (!config.enabled || config.action != ServerRequiredLinkingConfig.Action.KICK) { + return null; + } + + UUID playerUUID = profile.getId(); + String playerName = profile.getName(); + + Component kickReason = instance.getBlockReason(playerUUID, playerName, true).join(); + if (kickReason != null) { + return discordSRV.getAdventure().asNative(kickReason); + } + + return null; + } + + public static void onPlayerMove(ServerPlayerEntity player, PlayerMoveC2SPacket packet, CallbackInfo ci) { + if (instance == null || !instance.enabled) return; + Component freezeReason = instance.frozen.get(player.getUuid()); + if (freezeReason == null) { + return; + } + + BlockPos from = player.getBlockPos(); + BlockPos to = new BlockPos(MathHelper.floor(packet.getX(player.getX())), MathHelper.floor(packet.getY(player.getY())), MathHelper.floor(packet.getZ(player.getZ()))); + if (from.getX() == to.getX() && from.getY() >= to.getY() && from.getZ() == to.getZ()) { + return; + } + + player.requestTeleport(from.getX() + 0.5, from.getY(), from.getZ() + 0.5); + IPlayer iPlayer = instance.discordSRV.playerProvider().player(player); + iPlayer.sendMessage(freezeReason); + + ci.cancel(); + } + + public static void onCommandExecute(ParseResults parseResults, String command, CallbackInfo ci) { + if (instance == null || !instance.enabled) return; + FabricDiscordSRV discordSRV = instance.discordSRV; + ServerPlayerEntity playerEntity = parseResults.getContext().getSource().getPlayer(); + if (playerEntity == null) return; + + if (!instance.isFrozen(playerEntity)) { + return; + } + + if (command.startsWith("/")) command = command.substring(1); + if (command.equals("discord link") || command.equals("link")) { + + FabricPlayer player = discordSRV.playerProvider().player(playerEntity); + + UUID uuid = player.uniqueId(); + + if (instance.linkCheckRateLimit.getIfPresent(uuid) != null) { + player.sendMessage(discordSRV.messagesConfig(player).pleaseWaitBeforeRunningThatCommandAgain.asComponent()); + return; + } + instance.linkCheckRateLimit.put(uuid, true); + + player.sendMessage(discordSRV.messagesConfig(player).checkingLinkStatus.asComponent()); + + instance.getBlockReason(uuid, player.username(), false).whenComplete((reason, t) -> { + if (t != null) { + return; + } + + if (reason == null) { + instance.frozen.remove(uuid); + player.sendMessage(discordSRV.messagesConfig(player).nowLinked1st.asComponent()); + } else { + instance.freeze(player, reason); + } + }); + } + + ci.cancel(); + } + @Override public ServerRequiredLinkingConfig config() { return discordSRV.config().requiredLinking; } + // + // Kick + // + @Override public void enable() { super.enable(); @@ -83,6 +175,10 @@ public void enable() { this.enabled = true; } + // + // Freeze + // + public void register() { ServerMessageEvents.ALLOW_CHAT_MESSAGE.register(this::allowChatMessage); ServerConfigurationConnectionEvents.CONFIGURE.register(this::onPlayerPreLogin); @@ -119,42 +215,6 @@ public ServerRequiredLinkingConfig.Action action() { return config().action; } - // - // Kick - // - - @Nullable - public static Text checkCanJoin(GameProfile profile) { - if (instance == null || (instance.discordSRV != null && instance.discordSRV.status() != DiscordSRV.Status.CONNECTED)) { - return Text.of("Currently unavailable to check link status because the server is still connecting to Discord.\n\nTry again in a minute."); - } - if (!instance.enabled) return null; - - FabricDiscordSRV discordSRV = instance.discordSRV; - assert discordSRV != null; - ServerRequiredLinkingConfig config = instance.config(); - if (!config.enabled || config.action != ServerRequiredLinkingConfig.Action.KICK) { - return null; - } - - UUID playerUUID = profile.getId(); - String playerName = profile.getName(); - - Component kickReason = instance.getBlockReason(playerUUID, playerName, true).join(); - if (kickReason != null) { - return discordSRV.getAdventure().asNative(kickReason); - } - - return null; - } - - // - // Freeze - // - - private final Map frozen = new ConcurrentHashMap<>(); - private final List loginsHandled = new CopyOnWriteArrayList<>(); - private boolean isFrozen(ServerPlayerEntity player) { Component freezeReason = frozen.get(player.getUuid()); if (freezeReason == null) { @@ -182,18 +242,17 @@ private boolean allowChatMessage(SignedMessage signedMessage, ServerPlayerEntity } private void onPlayerPreLogin(ServerConfigurationNetworkHandler handler, MinecraftServer minecraftServer) { - if(!enabled) return; + if (!enabled) return; UUID playerUUID = handler.getDebugProfile().getId(); loginsHandled.add(playerUUID); handleLogin(playerUUID, handler.getDebugProfile().getName()); } - private void onPlayerJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSender packetSender, MinecraftServer minecraftServer) { - if(!enabled) return; + if (!enabled) return; UUID playerUUID = serverPlayNetworkHandler.player.getUuid(); - if(!loginsHandled.contains(playerUUID)) { + if (!loginsHandled.contains(playerUUID)) { handleLogin(playerUUID, serverPlayNetworkHandler.player.getName().getString()); } @@ -211,7 +270,7 @@ private void onPlayerJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, Pac } private void onPlayerQuit(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) { - if(!enabled) return; + if (!enabled) return; UUID playerUUID = serverPlayNetworkHandler.player.getUuid(); loginsHandled.remove(playerUUID); frozen.remove(playerUUID); @@ -238,66 +297,4 @@ private void handleLogin(UUID playerUUID, String username) { frozen.put(playerUUID, blockReason); } } - - public static void onPlayerMove(ServerPlayerEntity player, PlayerMoveC2SPacket packet, CallbackInfo ci) { - if(instance == null || !instance.enabled) return; - Component freezeReason = instance.frozen.get(player.getUuid()); - if (freezeReason == null) { - return; - } - - BlockPos from = player.getBlockPos(); - BlockPos to = new BlockPos(MathHelper.floor(packet.getX(player.getX())), MathHelper.floor(packet.getY(player.getY())), MathHelper.floor(packet.getZ(player.getZ()))); - if(from.getX() == to.getX() && from.getY() >= to.getY() && from.getZ() == to.getZ()) { - return; - } - - player.requestTeleport(from.getX() + 0.5, from.getY(), from.getZ() + 0.5); - IPlayer iPlayer = instance.discordSRV.playerProvider().player(player); - iPlayer.sendMessage(freezeReason); - - ci.cancel(); - } - - public static void onCommandExecute(ParseResults parseResults, String command, CallbackInfo ci) { - if(instance == null || !instance.enabled) return; - FabricDiscordSRV discordSRV = instance.discordSRV; - ServerPlayerEntity playerEntity = parseResults.getContext().getSource().getPlayer(); - if(playerEntity == null) return; - - if (!instance.isFrozen(playerEntity)) { - return; - } - - if(command.startsWith("/")) command = command.substring(1); - if(command.equals("discord link") || command.equals("link")) { - - FabricPlayer player = discordSRV.playerProvider().player(playerEntity); - - UUID uuid = player.uniqueId(); - - if (instance.linkCheckRateLimit.getIfPresent(uuid) != null) { - player.sendMessage(discordSRV.messagesConfig(player).pleaseWaitBeforeRunningThatCommandAgain.asComponent()); - return; - } - instance.linkCheckRateLimit.put(uuid, true); - - player.sendMessage(discordSRV.messagesConfig(player).checkingLinkStatus.asComponent()); - - instance.getBlockReason(uuid, player.username(), false).whenComplete((reason, t) -> { - if (t != null) { - return; - } - - if (reason == null) { - instance.frozen.remove(uuid); - player.sendMessage(discordSRV.messagesConfig(player).nowLinked1st.asComponent()); - } else { - instance.freeze(player, reason); - } - }); - } - - ci.cancel(); - } } From d5d96972d89ff2be746f4d0945056b40aaddb140 Mon Sep 17 00:00:00 2001 From: IxPrumxI Date: Wed, 22 Jan 2025 03:32:00 +0300 Subject: [PATCH 50/51] This got messed up while reformating and cleaning up Signed-off-by: IxPrumxI --- .../FabricRequiredLinkingModule.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java index 29d1063d..1b86a456 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java @@ -72,6 +72,10 @@ public FabricRequiredLinkingModule(FabricDiscordSRV discordSRV) { instance = this; } + // + // Kick + // + @Nullable public static Text checkCanJoin(GameProfile profile) { if (instance == null || (instance.discordSRV != null && instance.discordSRV.status() != DiscordSRV.Status.CONNECTED)) { @@ -97,6 +101,10 @@ public static Text checkCanJoin(GameProfile profile) { return null; } + // + // Freeze + // + public static void onPlayerMove(ServerPlayerEntity player, PlayerMoveC2SPacket packet, CallbackInfo ci) { if (instance == null || !instance.enabled) return; Component freezeReason = instance.frozen.get(player.getUuid()); @@ -164,10 +172,6 @@ public ServerRequiredLinkingConfig config() { return discordSRV.config().requiredLinking; } - // - // Kick - // - @Override public void enable() { super.enable(); @@ -175,10 +179,6 @@ public void enable() { this.enabled = true; } - // - // Freeze - // - public void register() { ServerMessageEvents.ALLOW_CHAT_MESSAGE.register(this::allowChatMessage); ServerConfigurationConnectionEvents.CONFIGURE.register(this::onPlayerPreLogin); @@ -215,6 +215,10 @@ public ServerRequiredLinkingConfig.Action action() { return config().action; } + // + // Freeze + // + private boolean isFrozen(ServerPlayerEntity player) { Component freezeReason = frozen.get(player.getUuid()); if (freezeReason == null) { From 8095977cc9faa585d9fe27f094e2d65c26a9211e Mon Sep 17 00:00:00 2001 From: Vankka Date: Mon, 3 Feb 2025 17:31:27 +0200 Subject: [PATCH 51/51] Cleanup code style --- .../FabricGameCommandExecutionHelper.java | 17 ++++++++---- .../fabric/console/FabricConsole.java | 3 ++- .../FabricCommandFeedbackExecutor.java | 10 ++++++- .../mixin/PlayerAdvancementTrackerMixin.java | 1 + .../fabric/module/AbstractFabricModule.java | 1 + .../fabric/module/ban/FabricBanModule.java | 26 ++++++++++++++----- .../module/chat/FabricAdvancementModule.java | 1 + .../fabric/module/chat/FabricChatModule.java | 1 + .../fabric/module/chat/FabricDeathModule.java | 2 +- .../fabric/module/chat/FabricJoinModule.java | 3 ++- .../fabric/module/chat/FabricQuitModule.java | 1 + .../fabric/player/FabricPlayer.java | 1 - .../fabric/player/FabricPlayerProvider.java | 4 ++- .../fabric/plugin/FabricModManager.java | 4 ++- .../FabricRequiredLinkingModule.java | 7 ++++- 15 files changed, 62 insertions(+), 20 deletions(-) diff --git a/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java b/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java index b3fddd41..66165ec9 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java +++ b/fabric/src/main/java/com/discordsrv/fabric/command/game/FabricGameCommandExecutionHelper.java @@ -22,6 +22,7 @@ import com.discordsrv.fabric.FabricDiscordSRV; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.ParseResults; +import com.mojang.brigadier.context.ParsedCommandNode; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.RootCommandNode; @@ -35,6 +36,7 @@ import java.util.stream.Collectors; public class FabricGameCommandExecutionHelper implements GameCommandExecutionHelper { + protected final FabricDiscordSRV discordSRV; private final CommandDispatcher dispatcher; @@ -60,8 +62,9 @@ public CompletableFuture> suggestCommands(List parts) { return CompletableFuture.completedFuture(data); } - if (!parse.getContext().getNodes().isEmpty()) { - CommandNode lastNode = parse.getContext().getNodes().getLast().getNode(); + List> nodes = parse.getContext().getNodes(); + if (!nodes.isEmpty()) { + CommandNode lastNode = nodes.getLast().getNode(); if (lastNode.getChildren().isEmpty() && lastNode.getRedirect() == null) { // We reached the end of the command tree. Suggest the full command as a valid command. return CompletableFuture.completedFuture(Collections.singletonList(fullCommand)); @@ -75,7 +78,7 @@ public CompletableFuture> suggestCommands(List parts) { if (data.isEmpty()) { // Suggestions are empty, Likely the user is still typing an argument. // If the context is empty, We search all commands from the root. - CommandNode lastNode = !parse.getContext().getNodes().isEmpty() ? parse.getContext().getNodes().getLast().getNode() : parse.getContext().getRootNode(); + CommandNode lastNode = !nodes.isEmpty() ? nodes.getLast().getNode() : parse.getContext().getRootNode(); for (CommandNode child : lastNode.getChildren()) { if (child.getName().toLowerCase().startsWith(parts.getLast().toLowerCase())) { @@ -112,7 +115,12 @@ public boolean isSameCommand(String command1, String command2) { } private CompletableFuture> getRootCommands() { - return CompletableFuture.completedFuture(dispatcher.getRoot().getChildren().stream().map(CommandNode::getName).collect(Collectors.toList())); + return CompletableFuture.completedFuture( + dispatcher.getRoot().getChildren() + .stream() + .map(CommandNode::getName) + .collect(Collectors.toList()) + ); } // Split the error message if it's too long on a period or a comma. If the message reached 97 characters, split at that point and continue. @@ -143,5 +151,4 @@ private List splitErrorMessage(String message) { return parts; } - } diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java b/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java index 529084df..ea023299 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java +++ b/fabric/src/main/java/com/discordsrv/fabric/console/FabricConsole.java @@ -41,7 +41,8 @@ public FabricConsole(FabricDiscordSRV discordSRV) { super(discordSRV, discordSRV.getServer().getCommandSource()); this.loggingBackend = Log4JLoggerImpl.getRoot(); - Function, ServerCommandSource> commandSenderProvider = consumer -> new FabricCommandFeedbackExecutor(discordSRV.getServer(), consumer).getCommandSource(); + Function, ServerCommandSource> commandSenderProvider = + consumer -> new FabricCommandFeedbackExecutor(discordSRV.getServer(), consumer).getCommandSource(); this.executorProvider = consumer -> new FabricCommandExecutor(discordSRV, commandSenderProvider.apply(consumer)); } diff --git a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandFeedbackExecutor.java b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandFeedbackExecutor.java index b7602acb..d506acb2 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandFeedbackExecutor.java +++ b/fabric/src/main/java/com/discordsrv/fabric/console/executor/FabricCommandFeedbackExecutor.java @@ -43,7 +43,15 @@ public FabricCommandFeedbackExecutor(MinecraftServer server, Consumer public ServerCommandSource getCommandSource() { ServerWorld serverWorld = server.getOverworld(); return new ServerCommandSource( - this, serverWorld == null ? Vec3d.ZERO : Vec3d.of(serverWorld.getSpawnPos()), Vec2f.ZERO, serverWorld, 4, "DiscordSRV", Text.literal("DiscordSRV"), server, null + this, + serverWorld == null ? Vec3d.ZERO : Vec3d.of(serverWorld.getSpawnPos()), + Vec2f.ZERO, + serverWorld, + 4, + "DiscordSRV", + Text.literal("DiscordSRV"), + server, + null ); } diff --git a/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java b/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java index ba7d7ab1..645dea26 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java +++ b/fabric/src/main/java/com/discordsrv/fabric/mixin/PlayerAdvancementTrackerMixin.java @@ -30,6 +30,7 @@ @Mixin(PlayerAdvancementTracker.class) public class PlayerAdvancementTrackerMixin { + @Shadow private ServerPlayerEntity owner; diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java index 05f2c837..478f8a48 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/AbstractFabricModule.java @@ -22,6 +22,7 @@ import com.discordsrv.fabric.FabricDiscordSRV; public abstract class AbstractFabricModule extends AbstractModule { + protected boolean enabled = false; public AbstractFabricModule(FabricDiscordSRV discordSRV) { diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java index 51fc1ef0..bd8a22bf 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/ban/FabricBanModule.java @@ -21,6 +21,7 @@ import com.discordsrv.api.component.MinecraftComponent; import com.discordsrv.api.module.type.PunishmentModule; import com.discordsrv.api.punishment.Punishment; +import com.discordsrv.common.abstraction.player.IPlayer; import com.discordsrv.common.feature.bansync.BanSyncModule; import com.discordsrv.common.util.ComponentUtil; import com.discordsrv.fabric.FabricDiscordSRV; @@ -43,6 +44,7 @@ import java.util.concurrent.CompletableFuture; public class FabricBanModule extends AbstractFabricModule implements PunishmentModule.Bans { + private static FabricBanModule instance; public FabricBanModule(FabricDiscordSRV discordSRV) { @@ -55,13 +57,19 @@ public static void onBan(GameProfile gameProfile) { if (instance == null) return; FabricDiscordSRV discordSRV = instance.discordSRV; BanSyncModule module = discordSRV.getModule(BanSyncModule.class); - if (module != null) { - instance.getBan(gameProfile.getId()) - .whenComplete((punishment, t) -> { - if (punishment != null) - module.notifyBanned(Objects.requireNonNull(discordSRV.playerProvider().player(gameProfile.getId())), punishment); - }); + if (module == null) return; + + UUID playerUUID = gameProfile.getId(); + IPlayer player = discordSRV.playerProvider().player(gameProfile.getId()); + if (player == null) { + throw new RuntimeException("Player " + playerUUID + " not present in player provider"); } + + instance.getBan(playerUUID).whenComplete((punishment, t) -> { + if (punishment != null) { + module.notifyBanned(player, punishment); + } + }); } public static void onPardon(GameProfile gameProfile) { @@ -122,7 +130,11 @@ public CompletableFuture addBan( ServerPlayerEntity serverPlayerEntity = server.getPlayerManager().getPlayer(playerUUID); if (serverPlayerEntity != null) { - serverPlayerEntity.networkHandler.disconnect(reason != null ? discordSRV.getAdventure().asNative(reason.asAdventure()) : Text.translatable("multiplayer.disconnect.banned")); + serverPlayerEntity.networkHandler.disconnect( + reason != null + ? discordSRV.getAdventure().asNative(reason.asAdventure()) + : Text.translatable("multiplayer.disconnect.banned") + ); } } catch (Exception e) { discordSRV.logger().error("Failed to ban player", e); diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java index bf182eea..dd35094c 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricAdvancementModule.java @@ -29,6 +29,7 @@ import net.minecraft.server.network.ServerPlayerEntity; public class FabricAdvancementModule extends AbstractFabricModule { + private static FabricAdvancementModule instance; private final FabricDiscordSRV discordSRV; diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java index 3c363973..9818d86a 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricChatModule.java @@ -29,6 +29,7 @@ import net.minecraft.server.network.ServerPlayerEntity; public class FabricChatModule extends AbstractFabricModule { + private final FabricDiscordSRV discordSRV; public FabricChatModule(FabricDiscordSRV discordSRV) { diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java index 95c0e84f..45e70dba 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricDeathModule.java @@ -31,6 +31,7 @@ import net.minecraft.text.Text; public class FabricDeathModule extends AbstractFabricModule { + private final FabricDiscordSRV discordSRV; public FabricDeathModule(FabricDiscordSRV discordSRV) { @@ -60,5 +61,4 @@ private void onDeath(LivingEntity livingEntity, DamageSource damageSource) { ); } } - } diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java index 878d97b2..220400b4 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricJoinModule.java @@ -35,6 +35,7 @@ import java.util.Objects; public class FabricJoinModule extends AbstractFabricModule { + private final FabricDiscordSRV discordSRV; public FabricJoinModule(FabricDiscordSRV discordSRV) { @@ -51,7 +52,7 @@ private void onJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSen ServerPlayerEntity playerEntity = serverPlayNetworkHandler.player; MinecraftComponent component = getJoinMessage(playerEntity); - boolean firstJoin = Objects.requireNonNull(minecraftServer.getUserCache()).findByName(serverPlayNetworkHandler.player.getGameProfile().getName()).isEmpty(); + boolean firstJoin = Objects.requireNonNull(minecraftServer.getUserCache()).findByName(playerEntity.getGameProfile().getName()).isEmpty(); DiscordSRVPlayer player = discordSRV.playerProvider().player(playerEntity); discordSRV.eventBus().publish( diff --git a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java index bb184057..f1d0446e 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/module/chat/FabricQuitModule.java @@ -32,6 +32,7 @@ import net.minecraft.util.Formatting; public class FabricQuitModule extends AbstractFabricModule { + private final FabricDiscordSRV discordSRV; public FabricQuitModule(FabricDiscordSRV discordSRV) { diff --git a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java index 4960561c..3fdb7610 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java +++ b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayer.java @@ -99,5 +99,4 @@ public void removeChatSuggestions(Collection suggestions) { public String toString() { return "FabricPlayer{" + username() + "}"; } - } diff --git a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java index b7dcff79..0643da14 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java +++ b/fabric/src/main/java/com/discordsrv/fabric/player/FabricPlayerProvider.java @@ -27,6 +27,7 @@ import net.minecraft.server.network.ServerPlayerEntity; public class FabricPlayerProvider extends AbstractPlayerProvider { + private boolean enabled = false; public FabricPlayerProvider(FabricDiscordSRV discordSRV) { @@ -39,8 +40,9 @@ public FabricPlayerProvider(FabricDiscordSRV discordSRV) { @Override public void subscribe() { enabled = true; - if (discordSRV.getServer() == null || discordSRV.getServer().getPlayerManager() == null) + if (discordSRV.getServer() == null || discordSRV.getServer().getPlayerManager() == null) { return; // Server not started yet, So there's no players to add + } // Add players that are already connected for (ServerPlayerEntity player : discordSRV.getServer().getPlayerManager().getPlayerList()) { diff --git a/fabric/src/main/java/com/discordsrv/fabric/plugin/FabricModManager.java b/fabric/src/main/java/com/discordsrv/fabric/plugin/FabricModManager.java index bd5e02a6..1c348b6c 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/plugin/FabricModManager.java +++ b/fabric/src/main/java/com/discordsrv/fabric/plugin/FabricModManager.java @@ -43,7 +43,9 @@ public List getPlugins() { id, modContainer.getMetadata().getName(), modContainer.getMetadata().getVersion().toString(), - modContainer.getMetadata().getAuthors().stream().map(Person::getName).collect(Collectors.toList()) + modContainer.getMetadata().getAuthors().stream() + .map(Person::getName) + .collect(Collectors.toList()) ); }) .collect(Collectors.toList()); diff --git a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java index 1b86a456..fb72bc81 100644 --- a/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java +++ b/fabric/src/main/java/com/discordsrv/fabric/requiredlinking/FabricRequiredLinkingModule.java @@ -55,6 +55,7 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule { + private static FabricRequiredLinkingModule instance; private final Cache linkCheckRateLimit; private final Map frozen = new ConcurrentHashMap<>(); @@ -113,7 +114,11 @@ public static void onPlayerMove(ServerPlayerEntity player, PlayerMoveC2SPacket p } BlockPos from = player.getBlockPos(); - BlockPos to = new BlockPos(MathHelper.floor(packet.getX(player.getX())), MathHelper.floor(packet.getY(player.getY())), MathHelper.floor(packet.getZ(player.getZ()))); + BlockPos to = new BlockPos( + MathHelper.floor(packet.getX(player.getX())), + MathHelper.floor(packet.getY(player.getY())), + MathHelper.floor(packet.getZ(player.getZ())) + ); if (from.getX() == to.getX() && from.getY() >= to.getY() && from.getZ() == to.getZ()) { return; }