diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 04c2b2c..50e44fd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - target: [ bukkit, fabric, forge ] + target: [ bukkit, fabric, forge, neoforge ] name: Build ${{ matrix.target }} runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 4bb6260..d67acaa 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ target/ .idea .gradle **/build/ +**/run !src/**/build/ gradle-app.setting !gradle-wrapper.jar diff --git a/common/build.gradle b/common/build.gradle index 8cb6aff..6ab0912 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,6 +1,11 @@ plugins { id "java" id "java-library" + id "maven-publish" +} + +compileJava { + options.compilerArgs += "-g" } dependencies { @@ -34,3 +39,15 @@ shadowJar { minimize() } + +publishing { + publications { + maven(MavenPublication) { + groupId = 'com.cssbham' + artifactId = 'common' + version = '1.0.0' + + from components.java + } + } +} diff --git a/common/src/main/java/com/cssbham/cssminecraft/common/command/handler/MakeGreenCommandHandler.java b/common/src/main/java/com/cssbham/cssminecraft/common/command/handler/MakeGreenCommandHandler.java index b9ba9dd..8f178f7 100644 --- a/common/src/main/java/com/cssbham/cssminecraft/common/command/handler/MakeGreenCommandHandler.java +++ b/common/src/main/java/com/cssbham/cssminecraft/common/command/handler/MakeGreenCommandHandler.java @@ -45,13 +45,20 @@ public void handle(CommandSender sender, CommandContext context) { if (discordClientService.getDiscordClient().isMember(arg)) { sender.sendMessage(Component.text("Making you green...").color(NamedTextColor.GRAY)); try { - permissionPluginService.grantMemberRole(sender.getUuid()).get(); - } catch (InterruptedException | ExecutionException e) { + permissionPluginService.grantMemberRole(sender.getUuid()).whenComplete((v, err) -> { + if (err != null) { + sender.sendMessage(Component.text("There was a problem making you green. Try again later.") + .color(NamedTextColor.RED)); + throw new RuntimeException(err); + } + + sender.sendMessage(Component.text("Congratulations, you are now green!").color(NamedTextColor.GREEN)); + }); + } catch (Exception e) { sender.sendMessage(Component.text("There was a problem making you green. Try again later.") .color(NamedTextColor.RED)); throw new RuntimeException(e); } - sender.sendMessage(Component.text("Congratulations, you are now green!").color(NamedTextColor.GREEN)); } else { sender.sendMessage(Component.text("You don't appear to be a ").color(NamedTextColor.RED).append( Component.text("Member").color(NamedTextColor.GREEN) diff --git a/common/src/main/java/com/cssbham/cssminecraft/common/permission/LuckPermsPermissionPluginService.java b/common/src/main/java/com/cssbham/cssminecraft/common/permission/LuckPermsPermissionPluginService.java index d77e783..cb05dbf 100644 --- a/common/src/main/java/com/cssbham/cssminecraft/common/permission/LuckPermsPermissionPluginService.java +++ b/common/src/main/java/com/cssbham/cssminecraft/common/permission/LuckPermsPermissionPluginService.java @@ -20,7 +20,14 @@ public CompletableFuture grantMemberRole(UUID player) { user.data().add(Node.builder("group.member").build()); user.data().remove(Node.builder("group.guest").build()); } - ); + ).whenCompleteAsync((v, err) -> { + if (err != null) { + err.printStackTrace(); + return; + } + + System.out.println("Success"); + }); } @Override diff --git a/neoforge/build.gradle b/neoforge/build.gradle new file mode 100644 index 0000000..27ec48f --- /dev/null +++ b/neoforge/build.gradle @@ -0,0 +1,266 @@ +plugins { + id 'java-library' + id 'maven-publish' + id 'idea' + id 'net.neoforged.moddev' version '2.0.92' +} + +version = mod_version +group = mod_group_id + +repositories { + mavenLocal() +} + +base { + archivesName = mod_id + "-neoforge" +} + +java.toolchain.languageVersion = JavaLanguageVersion.of(21) + +jarJar.enabled = true + +neoForge { + // Specify the version of NeoForge to use. + version = project.neo_version + + parchment { + mappingsVersion = project.parchment_mappings_version + minecraftVersion = project.parchment_minecraft_version + } + + // This line is optional. Access Transformers are automatically detected + // accessTransformers.add('src/main/resources/META-INF/accesstransformer.cfg') + + // Default run configurations. + // These can be tweaked, removed, or duplicated as needed. + runs { + client { + client() + + // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id + } + + server { + server() + programArgument '--nogui' + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id + } + + // This run config launches GameTestServer and runs all registered gametests, then exits. + // By default, the server will crash when no gametests are provided. + // The gametest system is also enabled by default for other run configs under the /test command. + gameTestServer { + type = "gameTestServer" + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id + } + + data { + data() + + // example of overriding the workingDirectory set in configureEach above, uncomment if you want to use it + // gameDirectory = project.file('run-data') + + // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. + programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() + } + + // applies to all the run configs above + configureEach { + // Recommended logging data for a userdev environment + // The markers can be added/remove as needed separated by commas. + // "SCAN": For mods scan. + // "REGISTRIES": For firing of registry events. + // "REGISTRYDUMP": For getting the contents of all registries. + systemProperty 'forge.logging.markers', 'REGISTRIES' + + // Recommended logging level for the console + // You can set various levels here. + // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels + logLevel = org.slf4j.event.Level.DEBUG + } + } + + mods { + // define mod <-> source bindings + // these are used to tell the game which sources are for which mod + // mostly optional in a single mod project + // but multi mod projects should define one per mod + "${mod_id}" { + sourceSet(sourceSets.main) + sourceSet(project(":common").sourceSets.main) + } + } +} + +// Include resources generated by data generators. +sourceSets.main.resources { srcDir 'src/generated/resources' } + +compileJava { + options.compilerArgs += "-g" +} + +dependencies { + // Example mod dependency with JEI + // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime + // compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}" + // compileOnly "mezz.jei:jei-${mc_version}-forge-api:${jei_version}" + // runtimeOnly "mezz.jei:jei-${mc_version}-forge:${jei_version}" + + // Example mod dependency using a mod jar from ./libs with a flat dir repository + // This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar + // The group id is ignored when searching -- in this case, it is "blank" + // implementation "blank:coolmod-${mc_version}:${coolmod_version}" + + // Example mod dependency using a file as dependency + // implementation files("libs/coolmod-${mc_version}-${coolmod_version}.jar") + + // Example project dependency using a sister or child project: + // implementation project(":myproject") + + // For more info: + // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html + // http://www.gradle.org/docs/current/userguide/dependency_management.html + + // implementation "net.neoforged:neoforge:${neo_version}" + + /* compileOnly(jarJar("net.kyori:adventure-api:4.17.0")) { + exclude(module: "adventure-bom") + exclude(module: "annotations") + } + compileOnly(jarJar("net.kyori:adventure-text-serializer-gson:4.17.0")) { + exclude(module: "adventure-bom") + exclude(module: "adventure-api") + exclude(module: "annotations") + exclude(module: "auto-service-annotations") + exclude(module: "gson") + } */ + + jarJar(implementation(group: "net.kyori", name: "adventure-platform-neoforge", version: "6.0.0") { + exclude(module: "annotations") + exclude(module: "auto-service-annotations") + exclude(module: "gson") + }) + jarJar(implementation ("net.dv8tion:JDA:5.0.2") { + exclude(module: "opus-java") + exclude(module: "annotations") + exclude(module: "slf4j-api") + }) + jarJar(implementation ("club.minnced:discord-webhooks:0.8.4") { + exclude(module: "slf4j-api") + }) + jarJar(implementation("org.yaml:snakeyaml:2.2")) + jarJar(implementation("com.neovisionaries:nv-websocket-client:2.14")) + jarJar(implementation("com.squareup.okhttp3:okhttp:4.12.0")) + jarJar(implementation("org.apache.commons:commons-collections4:4.4")) + jarJar(implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.10")) + jarJar(implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.10")) + jarJar(implementation("org.jetbrains.kotlin:kotlin-stdlib-common:1.9.10")) + jarJar(implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.10")) + jarJar(implementation("com.squareup.okio:okio:3.6.0")) + jarJar(implementation("net.sf.trove4j:core:3.1.0")) + jarJar(implementation("com.fasterxml.jackson.core:jackson-core:2.17.2")) + jarJar(implementation("com.fasterxml.jackson:jackson-bom:2.17.2")) + jarJar(implementation("com.fasterxml.jackson.core:jackson-annotations:2.17.2")) + jarJar(implementation("com.fasterxml.jackson.core:jackson-databind:2.17.2")) + jarJar(implementation("org.json:json:20230618")) + + shadow(compileOnly(project(path: ":common"))) { + transitive(false) + } + // additionalRuntimeClasspath("org.yaml:snakeyaml:2.2") + // additionalRuntimeClasspath("net.dv8tion:JDA:5.0.2") + // additionalRuntimeClasspath("club.minnced:discord-webhooks:0.8.4") + // additionalRuntimeClasspath("com.cssbham:common:1.0.0") + // additionalRuntimeClasspath("net.kyori:adventure-api:4.17.0") + // additionalRuntimeClasspath("net.kyori:adventure-platform-neoforge:6.0.0") + // additionalRuntimeClasspath("net.kyori:adventure-text-serializer-gson:4.17.0") +} + +// tasks.shadowJar.enabled = false + +// This block of code expands all declared replace properties in the specified resource targets. +// A missing property will result in an error. Properties are expanded using ${} Groovy notation. +var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) { + var replaceProperties = [ + minecraft_version : minecraft_version, + minecraft_version_range: minecraft_version_range, + neo_version : neo_version, + neo_version_range : neo_version_range, + loader_version_range : loader_version_range, + mod_id : mod_id, + mod_name : mod_name, + mod_license : mod_license, + mod_version : mod_version, + mod_authors : mod_authors, + mod_description : mod_description + ] + inputs.properties replaceProperties + expand replaceProperties + from "src/main/templates" + into "build/generated/sources/modMetadata" +} + +// Include the output of "generateModMetadata" as an input directory for the build +// this works with both building through Gradle and the IDE. +sourceSets.main.resources.srcDir generateModMetadata +// To avoid having to run "generateModMetadata" manually, make it run on every project reload +neoForge.ideSyncTask generateModMetadata + +// IDEA no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior. +idea { + module { + downloadSources = true + downloadJavadoc = true + } +} +/* +tasks.shadowJar { + configurations = [project.configurations.shadow] + + dependencies { + exclude(dependency("net.kyori:adventure-platform-neoforge:6.0.0")) + } + + doLast { + copy { + from("build/generated/jarjar/META-INF/jarjar") + into("META-INF/jarjar") + } + } + + // exclude("net/**") + // exclude("META-INF/services/*") + // minimize() + + archiveFileName = "cssminecraft-neoforge-${project.version}.jar" +} + + */ + +tasks.shadowJar.enabled = false +/* +tasks.register("shadeCommon") { + copy { + from("../common/build/classes/main/com/cssbham/cssminecraft/common") + into("build/classes/") + } +} */ + +tasks.jar { + from("../common/build/classes/java/main/com/cssbham/cssminecraft/common") { + into("com/cssbham/cssminecraft/common") + } +} +/* +tasks.register("copyJarJar") { + copy { + from ("build/generated/jarjar/META-INF/jarjar") + into("META-INF/jarjar") + } +} + +tasks.copyJarJar.dependsOn(jarJar) +*/ + diff --git a/neoforge/gradle.properties b/neoforge/gradle.properties new file mode 100644 index 0000000..fcc5ca4 --- /dev/null +++ b/neoforge/gradle.properties @@ -0,0 +1,44 @@ +# Sets default memory used for gradle commands. Can be overridden by user or command line properties. +org.gradle.jvmargs=-Xmx2G +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.configuration-cache=true + +## Environment Properties +# You can find the latest versions here: https://projects.neoforged.net/neoforged/neoforge +# The Minecraft version must agree with the Neo version to get a valid artifact +minecraft_version=1.21.1 +# The Minecraft version range can use any release version of Minecraft as bounds. +# Snapshots, pre-releases, and release candidates are not guaranteed to sort properly +# as they do not follow standard versioning conventions. +minecraft_version_range=[1.21.1,1.22) +# The Neo version must agree with the Minecraft version to get a valid artifact +neo_version=21.1.176 +# The Neo version range can use any version of Neo as bounds +neo_version_range=[21,) +# The loader version range can only use the major version of FML as bounds +loader_version_range=[4,) + +parchment_minecraft_version=1.21.4 +parchment_mappings_version=2025.03.23 + +## Mod Properties + +# The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63} +# Must match the String constant located in the main mod class annotated with @Mod. +mod_id=cssminecraft +# The human-readable display name for the mod. +mod_name=CSS-Minecraft +# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. +mod_license=todo +# The mod version. See https://semver.org/ +mod_version=1.0.0 +# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. +# This should match the base package used for the mod sources. +# See https://maven.apache.org/guides/mini/guide-naming-conventions.html +mod_group_id=com.cssbham.cssminecraft.neoforge +# The authors of the mod. This is a simple text string that is used for display purposes in the mod list. +mod_authors= +# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list. +mod_description= diff --git a/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/CSSMinecraftLoader.java b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/CSSMinecraftLoader.java new file mode 100644 index 0000000..9d11763 --- /dev/null +++ b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/CSSMinecraftLoader.java @@ -0,0 +1,36 @@ +package com.cssbham.cssminecraft.neoforge; + +import net.neoforged.fml.common.Mod; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.server.ServerStartingEvent; +import net.neoforged.neoforge.event.server.ServerStoppingEvent; + +/** + * Entrypoint for Forge + */ +@Mod(value = "cssminecraft") +public class CSSMinecraftLoader { + + private final NeoForgeCSSMinecraftPlugin plugin; + + public CSSMinecraftLoader() { + this.plugin = new NeoForgeCSSMinecraftPlugin(); + NeoForge.EVENT_BUS.addListener(this::onServerStarted); + NeoForge.EVENT_BUS.addListener(this::onServerStopping); + } + + public void onServerStarted(ServerStartingEvent event) { + this.plugin.setServer(event.getServer()); + try { + this.plugin.enable(); + } catch (Exception e) { + this.plugin.getLogger().severe("Mod initialisation failed - disabling"); + this.plugin.disable(); + } + } + + public void onServerStopping(ServerStoppingEvent event) { + this.plugin.disable(); + } + +} diff --git a/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/NeoForgeCSSMinecraftPlugin.java b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/NeoForgeCSSMinecraftPlugin.java new file mode 100644 index 0000000..5bf0f5c --- /dev/null +++ b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/NeoForgeCSSMinecraftPlugin.java @@ -0,0 +1,75 @@ +package com.cssbham.cssminecraft.neoforge; + +import com.cssbham.cssminecraft.common.AbstractCSSMinecraftPlugin; +import com.cssbham.cssminecraft.common.adapter.ServerChatAdapter; +import com.cssbham.cssminecraft.common.command.CommandService; +import com.cssbham.cssminecraft.common.executor.ServerExecutor; +import com.cssbham.cssminecraft.common.logger.Logger; +import com.cssbham.cssminecraft.neoforge.adapter.ForgeServerChatAdapter; +import com.cssbham.cssminecraft.neoforge.command.ForgeCommandService; +import com.cssbham.cssminecraft.neoforge.executor.ForgeServerExecutor; +import com.cssbham.cssminecraft.neoforge.listener.ForgeEventAdapter; +import com.cssbham.cssminecraft.neoforge.logger.ForgeLogger; +import net.minecraft.server.MinecraftServer; +import net.neoforged.fml.loading.FMLPaths; + +import java.nio.file.Path; + +/** + * Implementation of CSS Minecraft Plugin for Forge + */ +public class NeoForgeCSSMinecraftPlugin extends AbstractCSSMinecraftPlugin { + + public static final String MOD_ID = "cssminecraft"; + private final ForgeLogger logger; + private ForgeServerChatAdapter serverChatAdapter; + + private MinecraftServer server; + private ForgeServerExecutor executor; + private ForgeCommandService commandService; + + public NeoForgeCSSMinecraftPlugin() { + this.logger = new ForgeLogger(MOD_ID); + } + + @Override + public void enable() { + this.serverChatAdapter = new ForgeServerChatAdapter(server); + this.executor = new ForgeServerExecutor(logger, server); + this.commandService = new ForgeCommandService(logger, executor, serverChatAdapter, server); + + super.enable(); + + ForgeEventAdapter eventAdapter = new ForgeEventAdapter(server, executor); + eventAdapter.bindPlatformToEventBus(super.getEventBus()); + } + + @Override + public Logger getLogger() { + return logger; + } + + @Override + public ServerChatAdapter provideServerChatAdapter() { + return serverChatAdapter; + } + + @Override + public Path provideConfigurationPath() { + return FMLPaths.CONFIGDIR.get().resolve(MOD_ID).resolve("config.yml"); + } + + @Override + public ServerExecutor provideServerExecutor() { + return executor; + } + + @Override + public CommandService provideCommandService() { + return commandService; + } + + public void setServer(MinecraftServer server) { + this.server = server; + } +} diff --git a/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/adapter/ForgeServerChatAdapter.java b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/adapter/ForgeServerChatAdapter.java new file mode 100644 index 0000000..0eb730a --- /dev/null +++ b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/adapter/ForgeServerChatAdapter.java @@ -0,0 +1,42 @@ +package com.cssbham.cssminecraft.neoforge.adapter; + +import com.cssbham.cssminecraft.common.adapter.ServerChatAdapter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.minecraft.core.RegistryAccess; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; + +import java.util.UUID; + +public class ForgeServerChatAdapter implements ServerChatAdapter { + + private final MinecraftServer server; + + public ForgeServerChatAdapter(MinecraftServer server) { + this.server = server; + } + + @Override + public void broadcastMessage(Component message) { + server.getPlayerList().broadcastSystemMessage(componentToMinecraftComponent(message), false); + } + + @Override + public void sendMessageToPlayer(UUID user, Component component) { + ServerPlayer player = server.getPlayerList().getPlayer(user); + if (null != player) { + player.sendSystemMessage(componentToMinecraftComponent(component)); + } + } + + @Override + public void sendMessageToConsole(Component component) { + server.sendSystemMessage(componentToMinecraftComponent(component)); + } + + public net.minecraft.network.chat.Component componentToMinecraftComponent(Component component) { + return net.minecraft.network.chat.Component.Serializer.fromJson(GsonComponentSerializer.gson().serializeToTree(component), RegistryAccess.EMPTY); + } + +} diff --git a/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/command/ForgeCommandService.java b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/command/ForgeCommandService.java new file mode 100644 index 0000000..f98ebda --- /dev/null +++ b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/command/ForgeCommandService.java @@ -0,0 +1,68 @@ +package com.cssbham.cssminecraft.neoforge.command; + +import com.cssbham.cssminecraft.common.adapter.ServerChatAdapter; +import com.cssbham.cssminecraft.common.command.AbstractCommandService; +import com.cssbham.cssminecraft.common.command.CommandContext; +import com.cssbham.cssminecraft.common.command.CommandSender; +import com.cssbham.cssminecraft.common.executor.ServerExecutor; +import com.cssbham.cssminecraft.common.logger.Logger; +import com.cssbham.cssminecraft.common.util.CommandUtil; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.server.MinecraftServer; + +import java.util.UUID; + +import static com.mojang.brigadier.arguments.StringArgumentType.getString; +import static com.mojang.brigadier.arguments.StringArgumentType.greedyString; +import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal; +import static com.mojang.brigadier.builder.RequiredArgumentBuilder.argument; + +public class ForgeCommandService extends AbstractCommandService { + + private final ServerChatAdapter chatAdapter; + + public ForgeCommandService(Logger logger, ServerExecutor executor, ServerChatAdapter chatAdapter, MinecraftServer server) { + super(logger, executor); + + this.chatAdapter = chatAdapter; + + for (String label : CommandUtil.ALL_COMMANDS) { + // this is "unsafe" only because brigadier is not obfuscated + server.getCommands().getDispatcher().register((LiteralArgumentBuilder) literal(label) + .executes(context -> { + super.execute( + getCommandSenderForSource((CommandSourceStack) context.getSource()), + new CommandContext(label, new String[0]) + ); + return 1; + }) + .then(argument("args", greedyString()) + .executes(context -> { + super.execute( + getCommandSenderForSource((CommandSourceStack) context.getSource()), + new CommandContext(label, getString(context, "args").split(" ")) + ); + return 1; + }))); + } + } + + private CommandSender getCommandSenderForSource(CommandSourceStack source) { + if (source.isPlayer()) { + return new CommandSender( + chatAdapter, + source.getPlayer().getUUID(), + source.getTextName(), + false + ); + } else { + return new CommandSender( + chatAdapter, + new UUID(0, 0), + source.getTextName(), + true + ); + } + } +} diff --git a/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/executor/ForgeServerExecutor.java b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/executor/ForgeServerExecutor.java new file mode 100644 index 0000000..b9a3d23 --- /dev/null +++ b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/executor/ForgeServerExecutor.java @@ -0,0 +1,21 @@ +package com.cssbham.cssminecraft.neoforge.executor; + +import com.cssbham.cssminecraft.common.executor.AsyncServerExecutor; +import com.cssbham.cssminecraft.common.logger.Logger; +import net.minecraft.server.MinecraftServer; + +public class ForgeServerExecutor extends AsyncServerExecutor { + + private final MinecraftServer server; + + public ForgeServerExecutor(Logger logger, MinecraftServer server) { + super(logger); + this.server = server; + } + + @Override + public void doSync(Runnable runnable) { + server.executeIfPossible(runnable); + } + +} diff --git a/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/listener/ForgeEventAdapter.java b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/listener/ForgeEventAdapter.java new file mode 100644 index 0000000..988cb7b --- /dev/null +++ b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/listener/ForgeEventAdapter.java @@ -0,0 +1,84 @@ +package com.cssbham.cssminecraft.neoforge.listener; + +import com.cssbham.cssminecraft.common.event.Event; +import com.cssbham.cssminecraft.common.event.EventBus; +import com.cssbham.cssminecraft.common.event.PlatformEventAdapter; +import com.cssbham.cssminecraft.common.event.events.PlayerJoinEvent; +import com.cssbham.cssminecraft.common.event.events.PlayerQuitEvent; +import com.cssbham.cssminecraft.common.event.events.ServerMessageEvent; +import com.cssbham.cssminecraft.common.executor.ServerExecutor; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.ServerChatEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; + +import java.util.Objects; + +public class ForgeEventAdapter implements PlatformEventAdapter { + + private final MinecraftServer server; + private final ServerExecutor executor; + + public ForgeEventAdapter(MinecraftServer server, ServerExecutor executor) { + this.server = server; + this.executor = executor; + } + + private EventBus eventBus; + + @Override + public void bindPlatformToEventBus(EventBus eventBus) { + this.eventBus = eventBus; + + NeoForge.EVENT_BUS.register(this); + } + + private void dispatchEvent(Event event) { + Objects.requireNonNull(event, "event bus not bound"); + + executor.doAsync(() -> eventBus.dispatch(event)); + } + + @SubscribeEvent(priority = EventPriority.HIGH) + public void onChat(ServerChatEvent event) { + ServerPlayer player = event.getPlayer(); + String name = event.getUsername(); + + dispatchEvent(new ServerMessageEvent( + player.getUUID(), + name, + (null == player.getDisplayName()) ? name : player.getDisplayName().getString(), + event.getRawText() + )); + } + + @SubscribeEvent + public void onLogin(PlayerEvent.PlayerLoggedInEvent event) { + Player player = event.getEntity(); + String name = player.getName().getString(); + + dispatchEvent(new PlayerJoinEvent( + player.getUUID(), + name, + (null == player.getDisplayName()) ? name : player.getDisplayName().getString(), + server.getPlayerCount() + )); + } + + @SubscribeEvent + public void onLogout(PlayerEvent.PlayerLoggedOutEvent event) { + Player player = event.getEntity(); + String name = player.getName().getString(); + + dispatchEvent(new PlayerQuitEvent( + player.getUUID(), + name, + (null == player.getDisplayName()) ? name : player.getDisplayName().getString(), + server.getPlayerCount() - 1 + )); + } +} diff --git a/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/logger/ForgeLogger.java b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/logger/ForgeLogger.java new file mode 100644 index 0000000..b536c08 --- /dev/null +++ b/neoforge/src/main/java/com/cssbham/cssminecraft/neoforge/logger/ForgeLogger.java @@ -0,0 +1,29 @@ +package com.cssbham.cssminecraft.neoforge.logger; + +import com.cssbham.cssminecraft.common.logger.AbstractLogger; +import org.apache.logging.log4j.LogManager; + +public class ForgeLogger extends AbstractLogger { + + private final org.apache.logging.log4j.Logger logger; + + public ForgeLogger(String name) { + this.logger = LogManager.getLogger(name); + } + + @Override + protected void logInfo(String string) { + logger.info(string); + } + + @Override + protected void logError(String string) { + logger.error(string); + } + + @Override + protected void logWarning(String string) { + logger.warn(string); + } + +} diff --git a/neoforge/src/main/templates/META-INF/neoforge.mods.toml b/neoforge/src/main/templates/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..4332c7c --- /dev/null +++ b/neoforge/src/main/templates/META-INF/neoforge.mods.toml @@ -0,0 +1,35 @@ + +modLoader="javafml" #mandatory +loaderVersion="${loader_version_range}" #mandatory +license="${mod_license}" + +[[mods]] #mandatory +modId="cssminecraft" +version="${mod_version}" +displayName="${mod_name}" +logoFile="logo.png" +authors="LMBishop" +description=''' + CSS' Minecraft plugin + ''' + +[[dependencies.cssminecraft]] +modId="neoforge" +type="required" +versionRange="${neo_version_range}" +ordering="NONE" +side="BOTH" + +[[dependencies.cssminecraft]] +modId="minecraft" +type="required" +versionRange="${minecraft_version_range}" +ordering="NONE" +side="BOTH" + +[[dependencies.cssminecraft]] +modId="luckperms" +type="required" +versionRange="*" +ordering="BEFORE" +side="SERVER" diff --git a/settings.gradle b/settings.gradle index b9d5520..37540d3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,14 +3,20 @@ pluginManagement { gradlePluginPortal() maven { url = "https://maven.fabricmc.net/" } maven { url = "https://maven.minecraftforge.net/" } + maven { url = 'https://maven.neoforged.net/releases' } } } +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' +} + rootProject.name = "css-minecraft" include( "common", "bukkit", "fabric", - "forge" + "forge", + "neoforge" ) \ No newline at end of file