diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index bbb2057..08b4c8b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -5,23 +5,27 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@72f2cec99f417b1a1c5e2e88945068983b7965f9 - - uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 - - uses: actions/setup-java@4075bfc1b51bf22876335ae1cd589602d60d8758 + - name: Setup Gradle + uses: GeyserMC/actions/setup-gradle-composite@master with: - distribution: 'temurin' - java-version: 21 + setup-java_java-version: 21 + + - name: Build Floodgate-Modded + run: ./gradlew build + - name: Publish to Modrinth + if: ${{ success() && github.repository == 'GeyserMC/Floodgate-Modded' && github.ref_name == 'master' }} uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232 env: MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} with: arguments: modrinth gradle-home-cache-cleanup: true + - name: Archive Artifacts - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 + uses: GeyserMC/actions/upload-multi-artifact@master if: success() with: - name: Floodgate Fabric - path: build/libs/floodgate-fabric.jar - if-no-files-found: error \ No newline at end of file + artifacts: | + Floodgate-Fabric:fabric/build/libs/floodgate-fabric.jar + Floodgate-NeoForge:neoforge/build/libs/floodgate-neoforge.jar diff --git a/README.md b/README.md index 15381f4..a1a7300 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,11 @@ -# Floodgate-Fabric -Fabric port of the hybrid mode plugin to allow for connections from Geyser to join online mode servers. +# Floodgate-Modded +Fabric and NeoForge ports of the hybrid mode plugin to allow for connections from Geyser to join online mode servers. -Download: https://ci.opencollab.dev/job/GeyserMC/job/Floodgate-Fabric/job/master/ +Hybrid mode mod to allow for connections from Geyser to join online mode servers. +Geyser is an open collaboration project by CubeCraft Games. + +See the Floodgate section in the GeyserMC Wiki for more info about what Floodgate is, how you setup Floodgate and known issues/caveats. +Additionally, it includes a more in-depth look into how Floodgate works and the Floodgate API. + +Wiki: https://wiki.geysermc.org/floodgate/ +Download: https://modrinth.com/mod/floodgate diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts new file mode 100644 index 0000000..4790079 --- /dev/null +++ b/build-logic/build.gradle.kts @@ -0,0 +1,23 @@ +plugins { + `kotlin-dsl` +} + +repositories { + gradlePluginPortal() + mavenCentral() + maven("https://maven.architectury.dev/") + maven("https://maven.fabricmc.net/") + maven("https://maven.neoforged.net/releases/") +} + +dependencies { + // Used to access version catalogue from the convention plugins + // this is OK as long as the same version catalog is used in the main build and build-logic + // see https://github.com/gradle/gradle/issues/15383#issuecomment-779893192 + implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) + implementation(libs.indra) + implementation(libs.shadow) + implementation(libs.architectury.plugin) + implementation(libs.architectury.loom) + implementation(libs.minotaur) +} diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts new file mode 100644 index 0000000..63bde18 --- /dev/null +++ b/build-logic/settings.gradle.kts @@ -0,0 +1,11 @@ +@file:Suppress("UnstableApiUsage") + +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} + +rootProject.name = "build-logic" \ No newline at end of file diff --git a/build-logic/src/main/kotlin/LibsAccessor.kt b/build-logic/src/main/kotlin/LibsAccessor.kt new file mode 100644 index 0000000..2a0c09e --- /dev/null +++ b/build-logic/src/main/kotlin/LibsAccessor.kt @@ -0,0 +1,6 @@ +import org.gradle.accessors.dm.LibrariesForLibs +import org.gradle.api.Project +import org.gradle.kotlin.dsl.getByType + +val Project.libs: LibrariesForLibs + get() = rootProject.extensions.getByType() \ No newline at end of file diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt new file mode 100644 index 0000000..f4c2269 --- /dev/null +++ b/build-logic/src/main/kotlin/extensions.kt @@ -0,0 +1,36 @@ +import org.gradle.api.Project +import org.gradle.api.artifacts.MinimalExternalModuleDependency +import org.gradle.api.artifacts.ProjectDependency +import org.gradle.api.provider.Provider + +val providedDependencies = mutableMapOf>() + +fun Project.provided(pattern: String, name: String, excludedOn: Int = 0b110) { + providedDependencies.getOrPut(project.name) { mutableSetOf() } + .add("${calcExclusion(pattern, 0b100, excludedOn)}:${calcExclusion(name, 0b10, excludedOn)}") +} + +fun Project.provided(dependency: ProjectDependency) = + provided(dependency.group!!, dependency.name) + +fun Project.provided(dependency: MinimalExternalModuleDependency) = + provided(dependency.module.group, dependency.module.name) + +fun Project.provided(provider: Provider) = + provided(provider.get()) + +fun getProvidedDependenciesForProject(projectName: String): MutableSet { + return providedDependencies.getOrDefault(projectName, emptySet()).toMutableSet() +} + +private fun calcExclusion(section: String, bit: Int, excludedOn: Int): String = + if (excludedOn and bit > 0) section else "" + +fun projectVersion(project: Project): String = + project.version.toString().replace("SNAPSHOT", "b" + buildNumber()) + +fun versionName(project: Project): String = + "Floodgate-" + project.name.replaceFirstChar { it.uppercase() } + "-" + projectVersion(project) + +fun buildNumber(): Int = + (System.getenv("GITHUB_RUN_NUMBER"))?.let { Integer.parseInt(it) } ?: -1 diff --git a/build-logic/src/main/kotlin/floodgate-modded.base-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate-modded.base-conventions.gradle.kts new file mode 100644 index 0000000..77ef1e8 --- /dev/null +++ b/build-logic/src/main/kotlin/floodgate-modded.base-conventions.gradle.kts @@ -0,0 +1,37 @@ +plugins { + `java-library` + id("net.kyori.indra") +} + +dependencies { + compileOnly("org.checkerframework", "checker-qual", "3.19.0") +} + +indra { + github("GeyserMC", "floodgate-modded") { + ci(true) + issues(true) + scm(true) + } + mitLicense() + + javaVersions { + target(21) + } +} + +tasks { + processResources { + filesMatching(listOf("fabric.mod.json", "META-INF/neoforge.mods.toml")) { + expand( + "id" to "floodgate", + "name" to "Floodgate", + "version" to project.version, + "description" to project.description, + "url" to "https://geysermc.org", + "author" to "GeyserMC", + "minecraft_version" to libs.versions.minecraft.version.get() + ) + } + } +} \ No newline at end of file diff --git a/build-logic/src/main/kotlin/floodgate-modded.build-logic.gradle.kts b/build-logic/src/main/kotlin/floodgate-modded.build-logic.gradle.kts new file mode 100644 index 0000000..ff9b567 --- /dev/null +++ b/build-logic/src/main/kotlin/floodgate-modded.build-logic.gradle.kts @@ -0,0 +1,14 @@ +repositories { + // mavenLocal() + mavenCentral() + maven("https://maven.fabricmc.net/") + maven("https://maven.neoforged.net/releases") + maven("https://repo.opencollab.dev/main/") + maven("https://jitpack.io") { + content { + includeGroupByRegex("com.github.*") + } + } + maven("https://oss.sonatype.org/content/repositories/snapshots/") + maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") +} \ No newline at end of file diff --git a/build-logic/src/main/kotlin/floodgate-modded.platform-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate-modded.platform-conventions.gradle.kts new file mode 100644 index 0000000..71b70a2 --- /dev/null +++ b/build-logic/src/main/kotlin/floodgate-modded.platform-conventions.gradle.kts @@ -0,0 +1,134 @@ +import net.fabricmc.loom.task.RemapJarTask + +plugins { + id("floodgate-modded.publish-conventions") + id("architectury-plugin") + id("dev.architectury.loom") + id("com.modrinth.minotaur") +} + +// These are all provided by Minecraft/server platforms +provided("com.google.code.gson", "gson") +provided("org.slf4j", ".*") +provided("com.google.guava", "guava") +provided("org.ow2.asm", "asm") +provided("com.nukkitx.fastutil", ".*") + +// these we just don't want to include +provided("org.checkerframework", ".*") +provided("com.google.errorprone", ".*") +provided("com.github.spotbugs", "spotbugs-annotations") +provided("com.google.code.findbugs", ".*") + +// cloud-fabric/cloud-neoforge jij's all cloud depends already +provided("org.incendo", ".*") +provided("io.leangen.geantyref", "geantyref") + +architectury { + minecraft = libs.versions.minecraft.version.get() +} + +loom { + silentMojangMappingsLicense() +} + +configurations { + create("includeTransitive").isTransitive = true +} + +dependencies { + minecraft(libs.minecraft) + mappings(loom.officialMojangMappings()) + + // These are under our own namespace + shadow(libs.floodgate.api) { isTransitive = false } + shadow(libs.floodgate.core) { isTransitive = false } + + // Requires relocation + shadow(libs.bstats) { isTransitive = false } + + // Shadow & relocate these since the (indirectly) depend on quite old dependencies + shadow(libs.guice) { isTransitive = false } + shadow(libs.configutils) { + exclude("org.checkerframework") + exclude("com.google.errorprone") + exclude("com.github.spotbugs") + exclude("com.nukkitx.fastutil") + } + +} + +tasks { + sourcesJar { + archiveClassifier.set("sources") + from(sourceSets.main.get().allSource) + } + + shadowJar { + // Mirrors the example fabric project, otherwise tons of dependencies are shaded that shouldn't be + configurations = listOf(project.configurations.shadow.get()) + + // Relocate these + relocate("org.bstats", "org.geysermc.floodgate.shadow.bstats") + relocate("com.google.inject", "org.geysermc.floodgate.shadow.google.inject") + relocate("org.yaml", "org.geysermc.floodgate.shadow.org.yaml") + + // The remapped shadowJar is the final desired mod jar + archiveVersion.set(project.version.toString()) + archiveClassifier.set("shaded") + } + + remapJar { + dependsOn(shadowJar) + inputFile.set(shadowJar.get().archiveFile) + archiveClassifier.set("") + archiveVersion.set("") + } + + register("remapModrinthJar", RemapJarTask::class) { + dependsOn(shadowJar) + inputFile.set(shadowJar.get().archiveFile) + archiveVersion.set(versionName(project)) + archiveClassifier.set("") + } + + // Readme sync + modrinth.get().dependsOn(tasks.modrinthSyncBody) +} + +afterEvaluate { + val providedDependencies = getProvidedDependenciesForProject(project.name) + + // These are shaded, no need to JiJ them + configurations["shadow"].resolvedConfiguration.resolvedArtifacts.forEach {shadowed -> + val string = "${shadowed.moduleVersion.id.group}:${shadowed.moduleVersion.id.name}" + println("Not including shadowed dependency: $string") + providedDependencies.add(string) + } + + configurations["includeTransitive"].resolvedConfiguration.resolvedArtifacts.forEach { dep -> + if (!providedDependencies.contains("${dep.moduleVersion.id.group}:${dep.moduleVersion.id.name}") + and !providedDependencies.contains("${dep.moduleVersion.id.group}:.*")) { + println("Including dependency via JiJ: ${dep.id}") + dependencies.add("include", dep.moduleVersion.id.toString()) + } else { + println("Not including ${dep.id} for ${project.name}!") + } + } +} + +modrinth { + token.set(System.getenv("MODRINTH_TOKEN")) // Even though this is the default value, apparently this prevents GitHub Actions caching the token? + projectId.set("bWrNNfkb") + versionName.set(versionName(project)) + versionNumber.set(projectVersion(project)) + versionType.set("release") + changelog.set("A changelog can be found at https://github.com/GeyserMC/Floodgate-Modded/commits") + + syncBodyFrom.set(rootProject.file("README.md").readText()) + + uploadFile.set(tasks.getByPath("remapModrinthJar")) + gameVersions.add(libs.minecraft.get().version as String) + gameVersions.add("1.21.1") + failSilently.set(false) +} diff --git a/build-logic/src/main/kotlin/floodgate-modded.publish-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate-modded.publish-conventions.gradle.kts new file mode 100644 index 0000000..fdfa4ef --- /dev/null +++ b/build-logic/src/main/kotlin/floodgate-modded.publish-conventions.gradle.kts @@ -0,0 +1,15 @@ +plugins { + id("floodgate-modded.shadow-conventions") + id("net.kyori.indra.publishing") +} + +indra { + publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/maven-snapshots") + publishReleasesTo("geysermc", "https://repo.opencollab.dev/maven-releases") +} + +publishing { + // skip shadow jar from publishing. Workaround for https://github.com/johnrengelman/shadow/issues/651 + val javaComponent = project.components["java"] as AdhocComponentWithVariants + javaComponent.withVariantsFromConfiguration(configurations["shadowRuntimeElements"]) { skip() } +} \ No newline at end of file diff --git a/build-logic/src/main/kotlin/floodgate-modded.shadow-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate-modded.shadow-conventions.gradle.kts new file mode 100644 index 0000000..e4affd7 --- /dev/null +++ b/build-logic/src/main/kotlin/floodgate-modded.shadow-conventions.gradle.kts @@ -0,0 +1,37 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +plugins { + id("floodgate-modded.base-conventions") + id("com.github.johnrengelman.shadow") +} + +tasks { + named("jar") { + archiveClassifier.set("unshaded") + from(project.rootProject.file("LICENSE")) + } + val shadowJar = named("shadowJar") { + archiveBaseName.set(project.name) + archiveVersion.set("") + archiveClassifier.set("") + + val sJar: ShadowJar = this + + doFirst { + providedDependencies[project.name]?.forEach { string -> + sJar.dependencies { + println("Excluding $string from ${project.name}") + exclude(dependency(string)) + } + } + + sJar.dependencies { + exclude(dependency("org.checkerframework:checker-qual:.*")) + exclude(dependency("org.jetbrains:annotations:.*")) + } + } + } + named("build") { + dependsOn(shadowJar) + } +} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 525d512..d81fbb1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,147 +1,24 @@ -import net.fabricmc.loom.task.RemapJarTask - plugins { - id("com.github.johnrengelman.shadow") version "8.1.1" - id("fabric-loom") version "1.6-SNAPSHOT" - id("java") - id("maven-publish") - id("com.modrinth.minotaur") version "2.+" -} - -loom { - accessWidenerPath = file("src/main/resources/floodgate.accesswidener") -} - -dependencies { - //to change the versions see the gradle.properties file - minecraft("com.mojang:minecraft:1.21") - mappings(loom.officialMojangMappings()) - modImplementation("net.fabricmc:fabric-loader:0.15.11") - - // Fabric API. This is technically optional, but you probably want it anyway. - modImplementation("net.fabricmc.fabric-api:fabric-api:0.100.1+1.21") - - // Base Floodgate - implementation("org.geysermc.floodgate:core:2.2.3-20240508.151752-4") - shadow("org.geysermc.floodgate:core:2.2.3-20240508.151752-4") { isTransitive = false } - shadow("org.geysermc.floodgate:api:2.2.3-20240508.151752-4") { isTransitive = false } - - // Requires relocation - shadow("org.bstats:bstats-base:3.0.2") - - // Shadow & relocate these since the (indirectly) depend on quite old dependencies - shadow("com.google.inject:guice:6.0.0") { isTransitive = false } - shadow("org.geysermc.configutils:configutils:1.0-SNAPSHOT") { - exclude("org.checkerframework") - exclude("com.google.errorprone") - exclude("com.github.spotbugs") - exclude("com.nukkitx.fastutil") - } - - include("aopalliance:aopalliance:1.0") - include("javax.inject:javax.inject:1") - include("jakarta.inject:jakarta.inject-api:2.0.1") - include("org.java-websocket:Java-WebSocket:1.5.2") - - // Just like Geyser, include these - include("org.geysermc.geyser", "common", "2.2.3-SNAPSHOT") - include("org.geysermc.cumulus", "cumulus", "1.1.2") - include("org.geysermc.event", "events", "1.1-SNAPSHOT") - include("org.lanternpowered", "lmbda", "2.0.0") // used in events - - // Geyser dependency for the fun injector mixin :))) - modCompileOnly("org.geysermc.geyser:fabric:2.2.3-SNAPSHOT") { isTransitive = false } - - // cloud - include("org.incendo:cloud-fabric:2.0.0-SNAPSHOT") - modImplementation("org.incendo:cloud-fabric:2.0.0-SNAPSHOT") - - // Lombok - compileOnly("org.projectlombok:lombok:1.18.32") - annotationProcessor("org.projectlombok:lombok:1.18.32") -} - -repositories { - // mavenLocal() - mavenCentral() - maven("https://maven.fabricmc.net/") - maven("https://repo.opencollab.dev/main/") - maven("https://jitpack.io") { - content { - includeGroupByRegex("com.github.*") - } - } - maven("https://oss.sonatype.org/content/repositories/snapshots/") - maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") -} - -java { - withSourcesJar() + `java-library` + id("floodgate-modded.build-logic") + alias(libs.plugins.lombok) apply false } -tasks { - shadowJar { - configurations = listOf(project.configurations.shadow.get()) - - relocate("org.bstats", "org.geysermc.floodgate.shadow.bstats") - relocate("com.google.inject", "org.geysermc.floodgate.shadow.google.inject") - relocate("org.yaml", "org.geysermc.floodgate.shadow.org.yaml") - } - - processResources { - filesMatching("fabric.mod.json") { - expand("version" to project.version) - } - } - - remapJar { - dependsOn(shadowJar) - mustRunAfter(shadowJar) - inputFile.set(shadowJar.get().archiveFile) - addNestedDependencies = true // todo? - archiveFileName.set("floodgate-fabric.jar") - } +val platforms = setOf( + projects.fabric, + projects.neoforge, + projects.mod +).map { it.dependencyProject } - register("remapModrinthJar", RemapJarTask::class) { - dependsOn(shadowJar) - inputFile.set(shadowJar.get().archiveFile) - addNestedDependencies = true - archiveVersion.set(project.version.toString() + "+build." + System.getenv("GITHUB_RUN_NUMBER")) - archiveClassifier.set("") +subprojects { + apply { + plugin("java-library") + plugin("io.freefair.lombok") + plugin("floodgate-modded.build-logic") } -} -publishing { - publications { - register("publish", MavenPublication::class) { - from(project.components["java"]) - - // skip shadow jar from publishing. Workaround for https://github.com/johnrengelman/shadow/issues/651 - val javaComponent = project.components["java"] as AdhocComponentWithVariants - javaComponent.withVariantsFromConfiguration(configurations["shadowRuntimeElements"]) { skip() } - } + when (this) { + in platforms -> plugins.apply("floodgate-modded.platform-conventions") + else -> plugins.apply("floodgate-modded.base-conventions") } - - repositories { - mavenLocal() - } -} - -modrinth { - token.set(System.getenv("MODRINTH_TOKEN")) // Prevent GitHub Actions from caching empty Modrinth token - projectId.set("bWrNNfkb") - versionNumber.set(project.version as String + "-" + System.getenv("GITHUB_RUN_NUMBER")) - versionType.set("beta") - changelog.set("A changelog can be found at https://github.com/GeyserMC/Floodgate-Fabric/commits") - - syncBodyFrom.set(rootProject.file("README.md").readText()) - - uploadFile.set(tasks.named("remapModrinthJar")) - gameVersions.addAll("1.21") - - loaders.add("fabric") - - dependencies { - required.project("fabric-api") - } -} +} \ No newline at end of file diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts new file mode 100644 index 0000000..7aef15a --- /dev/null +++ b/fabric/build.gradle.kts @@ -0,0 +1,46 @@ +architectury { + platformSetupLoomIde() + fabric() +} + +// Used to extend runtime/compile classpaths +val common: Configuration by configurations.creating +// Needed to read mixin config in the runServer task, and for the architectury transformer +// (e.g. the @ExpectPlatform annotation) +val developmentFabric: Configuration = configurations.getByName("developmentFabric") +// Our custom transitive include configuration +val includeTransitive: Configuration = configurations.getByName("includeTransitive") + +configurations { + compileClasspath.get().extendsFrom(configurations["common"]) + runtimeClasspath.get().extendsFrom(configurations["common"]) + developmentFabric.extendsFrom(configurations["common"]) +} + +dependencies { + modImplementation(libs.fabric.loader) + modApi(libs.fabric.api) + // "namedElements" configuration should be used to depend on different loom projects + common(project(":mod", configuration = "namedElements")) { isTransitive = false } + // Bundle transformed classes of the common module for production mod jar + shadow(project(path = ":mod", configuration = "transformProductionFabric")) { + isTransitive = false + } + + includeTransitive(libs.floodgate.core) + implementation(libs.floodgate.core) + implementation(libs.guice) + + modImplementation(libs.cloud.fabric) + include(libs.cloud.fabric) +} + +tasks { + remapJar { + archiveBaseName.set("floodgate-fabric") + } + + modrinth { + loaders.add("fabric") + } +} diff --git a/fabric/gradle.properties b/fabric/gradle.properties new file mode 100644 index 0000000..90ee7a2 --- /dev/null +++ b/fabric/gradle.properties @@ -0,0 +1 @@ +loom.platform=fabric \ No newline at end of file diff --git a/fabric/src/main/java/org/geysermc/floodgate/mod/util/fabric/MixinConfigPluginImpl.java b/fabric/src/main/java/org/geysermc/floodgate/mod/util/fabric/MixinConfigPluginImpl.java new file mode 100644 index 0000000..bf8f6d2 --- /dev/null +++ b/fabric/src/main/java/org/geysermc/floodgate/mod/util/fabric/MixinConfigPluginImpl.java @@ -0,0 +1,14 @@ +package org.geysermc.floodgate.mod.util.fabric; + +import net.fabricmc.loader.api.FabricLoader; + +public class MixinConfigPluginImpl { + + public static boolean isGeyserLoaded() { + return FabricLoader.getInstance().isModLoaded("geyser-fabric"); + } + + public static boolean applyProxyFix() { + return FabricLoader.getInstance().isModLoaded("fabricproxy-lite"); + } +} diff --git a/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/FabricFloodgateMod.java b/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/FabricFloodgateMod.java new file mode 100644 index 0000000..ed1a98c --- /dev/null +++ b/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/FabricFloodgateMod.java @@ -0,0 +1,54 @@ +package org.geysermc.floodgate.platform.fabric; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.floodgate.core.module.PluginMessageModule; +import org.geysermc.floodgate.core.module.ServerCommonModule; +import org.geysermc.floodgate.mod.FloodgateMod; +import org.geysermc.floodgate.mod.util.ModTemplateReader; +import org.geysermc.floodgate.platform.fabric.module.FabricCommandModule; +import org.geysermc.floodgate.platform.fabric.module.FabricPlatformModule; + +import java.nio.file.Path; + +public final class FabricFloodgateMod extends FloodgateMod implements ModInitializer { + + private ModContainer container; + + @Override + public void onInitialize() { + container = FabricLoader.getInstance().getModContainer("floodgate").orElseThrow(); + init( + new ServerCommonModule( + FabricLoader.getInstance().getConfigDir().resolve("floodgate"), + new ModTemplateReader() + ), + new FabricPlatformModule(), + new FabricCommandModule(), + new PluginMessageModule() + ); + + ServerLifecycleEvents.SERVER_STARTED.register(this::enable); + + if (isClient()) { + ClientLifecycleEvents.CLIENT_STOPPING.register($ -> this.disable()); + } else { + ServerLifecycleEvents.SERVER_STOPPING.register($ -> this.disable()); + } + } + + @Override + public @Nullable Path resourcePath(String file) { + return container.findPath(file).orElse(null); + } + + @Override + public boolean isClient() { + return FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT; + } +} diff --git a/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/listener/FabricEventRegistration.java b/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/listener/FabricEventRegistration.java new file mode 100644 index 0000000..80e486d --- /dev/null +++ b/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/listener/FabricEventRegistration.java @@ -0,0 +1,14 @@ +package org.geysermc.floodgate.platform.fabric.listener; + +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import org.geysermc.floodgate.core.platform.listener.ListenerRegistration; +import org.geysermc.floodgate.mod.listener.ModEventListener; + +public final class FabricEventRegistration implements ListenerRegistration { + @Override + public void register(ModEventListener listener) { + ServerPlayConnectionEvents.JOIN.register( + (handler, sender, server) -> listener.onPlayerJoin(handler.getPlayer().getUUID()) + ); + } +} diff --git a/src/main/java/org/geysermc/floodgate/module/FabricCommandModule.java b/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/module/FabricCommandModule.java similarity index 64% rename from src/main/java/org/geysermc/floodgate/module/FabricCommandModule.java rename to fabric/src/main/java/org/geysermc/floodgate/platform/fabric/module/FabricCommandModule.java index c02adb1..4d9ccb8 100644 --- a/src/main/java/org/geysermc/floodgate/module/FabricCommandModule.java +++ b/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/module/FabricCommandModule.java @@ -1,13 +1,15 @@ -package org.geysermc.floodgate.module; +package org.geysermc.floodgate.platform.fabric.module; import com.google.inject.Provides; import com.google.inject.Singleton; import lombok.SneakyThrows; import net.minecraft.commands.CommandSourceStack; -import org.geysermc.floodgate.platform.command.CommandUtil; -import org.geysermc.floodgate.player.FloodgateCommandPreprocessor; -import org.geysermc.floodgate.player.UserAudience; -import org.geysermc.floodgate.player.audience.FloodgateSenderMapper; +import org.geysermc.floodgate.core.module.CommandModule; +import org.geysermc.floodgate.core.platform.command.CommandUtil; +import org.geysermc.floodgate.core.player.FloodgateCommandPreprocessor; +import org.geysermc.floodgate.core.player.UserAudience; +import org.geysermc.floodgate.core.player.audience.FloodgateSenderMapper; +import org.geysermc.floodgate.mod.util.ModCommandUtil; import org.incendo.cloud.CommandManager; import org.incendo.cloud.execution.ExecutionCoordinator; import org.incendo.cloud.fabric.FabricCommandManager; @@ -23,6 +25,7 @@ public CommandManager commandManager(CommandUtil commandUtil) { new FloodgateSenderMapper<>(commandUtil) ); commandManager.registerCommandPreProcessor(new FloodgateCommandPreprocessor<>(commandUtil)); + ((ModCommandUtil) commandUtil).setCommandManager(commandManager); return commandManager; } diff --git a/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/module/FabricPlatformModule.java b/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/module/FabricPlatformModule.java new file mode 100644 index 0000000..2f4cf18 --- /dev/null +++ b/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/module/FabricPlatformModule.java @@ -0,0 +1,40 @@ +package org.geysermc.floodgate.platform.fabric.module; + +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.google.inject.name.Named; +import org.geysermc.floodgate.core.platform.listener.ListenerRegistration; +import org.geysermc.floodgate.core.platform.pluginmessage.PluginMessageUtils; +import org.geysermc.floodgate.core.pluginmessage.PluginMessageRegistration; +import org.geysermc.floodgate.mod.listener.ModEventListener; +import org.geysermc.floodgate.mod.module.ModPlatformModule; +import org.geysermc.floodgate.platform.fabric.listener.FabricEventRegistration; +import org.geysermc.floodgate.platform.fabric.pluginmessage.FabricPluginMessageRegistration; +import org.geysermc.floodgate.platform.fabric.pluginmessage.FabricPluginMessageUtils; + +public class FabricPlatformModule extends ModPlatformModule { + + @Provides + @Singleton + public ListenerRegistration listenerRegistration() { + return new FabricEventRegistration(); + } + + @Provides + @Singleton + public PluginMessageUtils pluginMessageUtils() { + return new FabricPluginMessageUtils(); + } + + @Provides + @Singleton + public PluginMessageRegistration pluginMessageRegister() { + return new FabricPluginMessageRegistration(); + } + + @Provides + @Named("implementationName") + public String implementationName() { + return "Fabric"; + } +} diff --git a/src/main/java/org/geysermc/floodgate/pluginmessage/FabricPluginMessageRegistration.java b/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/pluginmessage/FabricPluginMessageRegistration.java similarity index 85% rename from src/main/java/org/geysermc/floodgate/pluginmessage/FabricPluginMessageRegistration.java rename to fabric/src/main/java/org/geysermc/floodgate/platform/fabric/pluginmessage/FabricPluginMessageRegistration.java index ee5b781..d9da35c 100644 --- a/src/main/java/org/geysermc/floodgate/pluginmessage/FabricPluginMessageRegistration.java +++ b/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/pluginmessage/FabricPluginMessageRegistration.java @@ -1,11 +1,13 @@ -package org.geysermc.floodgate.pluginmessage; +package org.geysermc.floodgate.platform.fabric.pluginmessage; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import org.geysermc.floodgate.pluginmessage.payloads.FormPayload; -import org.geysermc.floodgate.pluginmessage.payloads.PacketPayload; -import org.geysermc.floodgate.pluginmessage.payloads.SkinPayload; -import org.geysermc.floodgate.pluginmessage.payloads.TransferPayload; +import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel; +import org.geysermc.floodgate.core.pluginmessage.PluginMessageRegistration; +import org.geysermc.floodgate.mod.pluginmessage.payloads.FormPayload; +import org.geysermc.floodgate.mod.pluginmessage.payloads.PacketPayload; +import org.geysermc.floodgate.mod.pluginmessage.payloads.SkinPayload; +import org.geysermc.floodgate.mod.pluginmessage.payloads.TransferPayload; public class FabricPluginMessageRegistration implements PluginMessageRegistration { @Override diff --git a/src/main/java/org/geysermc/floodgate/pluginmessage/FabricPluginMessageUtils.java b/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/pluginmessage/FabricPluginMessageUtils.java similarity index 61% rename from src/main/java/org/geysermc/floodgate/pluginmessage/FabricPluginMessageUtils.java rename to fabric/src/main/java/org/geysermc/floodgate/platform/fabric/pluginmessage/FabricPluginMessageUtils.java index 6a5b3b4..9aa1094 100644 --- a/src/main/java/org/geysermc/floodgate/pluginmessage/FabricPluginMessageUtils.java +++ b/fabric/src/main/java/org/geysermc/floodgate/platform/fabric/pluginmessage/FabricPluginMessageUtils.java @@ -1,21 +1,14 @@ -package org.geysermc.floodgate.pluginmessage; +package org.geysermc.floodgate.platform.fabric.pluginmessage; -import io.netty.buffer.Unpooled; -import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; -import org.geysermc.floodgate.MinecraftServerHolder; -import org.geysermc.floodgate.api.FloodgateApi; -import org.geysermc.floodgate.api.InstanceHolder; -import org.geysermc.floodgate.platform.pluginmessage.PluginMessageUtils; -import org.geysermc.floodgate.pluginmessage.payloads.FormPayload; -import org.geysermc.floodgate.pluginmessage.payloads.PacketPayload; -import org.geysermc.floodgate.pluginmessage.payloads.SkinPayload; -import org.geysermc.floodgate.pluginmessage.payloads.TransferPayload; +import org.geysermc.floodgate.core.platform.pluginmessage.PluginMessageUtils; +import org.geysermc.floodgate.mod.MinecraftServerHolder; +import org.geysermc.floodgate.mod.pluginmessage.payloads.FormPayload; +import org.geysermc.floodgate.mod.pluginmessage.payloads.PacketPayload; +import org.geysermc.floodgate.mod.pluginmessage.payloads.SkinPayload; +import org.geysermc.floodgate.mod.pluginmessage.payloads.TransferPayload; import java.util.Objects; import java.util.UUID; diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..62a1c73 --- /dev/null +++ b/fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,30 @@ +{ + "schemaVersion": 1, + "id": "$id", + "version": "$version", + "name": "$name", + "description": "$description", + "authors": [ + "$author" + ], + "contact": { + "website": "$url", + "repo": "https://github.com/GeyserMC/Floodgate-Modded" + }, + "license": "MIT", + "environment": "*", + "entrypoints": { + "main": [ + "org.geysermc.floodgate.platform.fabric.FabricFloodgateMod" + ] + }, + "accessWidener": "floodgate.accesswidener", + "mixins": [ + "floodgate.mixins.json" + ], + "depends": { + "fabricloader": ">=0.15.10", + "fabric": "*", + "minecraft": ">=$minecraft_version" + } +} diff --git a/gradle.properties b/gradle.properties index 573a53c..a5ca268 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,9 @@ -# Done to increase the memory available to gradle. org.gradle.jvmargs=-Xmx2G +org.gradle.daemon=false +org.gradle.caching=true +org.gradle.vfs.watch=false + # Mod Properties -version=2.2.3-SNAPSHOT +version=2.2.4-SNAPSHOT group=org.geysermc.floodgate -archives_base_name=floodgate-fabric +id=floodgate-modded diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..bae1d82 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,57 @@ +[versions] +geyser = "2.2.3-SNAPSHOT" +blossom = "1.2.0" +indra = "3.1.3" +shadow = "8.1.1" +architectury-plugin = "3.4-SNAPSHOT" +architectury-loom = "1.7-SNAPSHOT" +minecraft-version = "1.21" +minotaur = "2.+" +guice = "6.0.0" +cloud = "2.0.0-beta.7" +lombok = "8.6" +bstats = "3.0.2" +configutils = "1.0-SNAPSHOT" +mixin = "0.8.5" +asm = "5.2" +floodgate = "core-repackage-2.2.3-SNAPSHOT" + +# fabric +fabric-loader = "0.15.11" +fabric-api = "0.100.1+1.21" + +# neoforge +neoforge-version = "21.0.87-beta" + +[libraries] +floodgate-core = { group = "org.geysermc.floodgate", name = "core", version.ref = "floodgate" } +floodgate-api = { group = "org.geysermc.floodgate", name = "api", version.ref = "floodgate" } + +geyser-fabric = { group = "org.geysermc.geyser", name = "fabric", version.ref = "geyser" } +geyser-mod = { group = "org.geysermc.geyser", name = "mod", version.ref = "geyser" } +geyser-core = { group = "org.geysermc.geyser", name = "core", version.ref = "geyser" } +indra = { group = "net.kyori", name = "indra-common", version.ref = "indra" } +shadow = { group = "com.github.johnrengelman", name = "shadow", version.ref = "shadow" } +architectury-plugin = { group = "architectury-plugin", name = "architectury-plugin.gradle.plugin", version.ref = "architectury-plugin" } +architectury-loom = { group = "dev.architectury.loom", name = "dev.architectury.loom.gradle.plugin", version.ref = "architectury-loom" } +guice = { group = "com.google.inject", name = "guice", version.ref = "guice" } +bstats = { group = "org.bstats", name = "bstats-base", version.ref = "bstats" } +configutils = { group = "org.geysermc.configutils", name = "configutils", version.ref = "configutils" } +cloud-fabric = { group = "org.incendo", name = "cloud-fabric", version.ref = "cloud" } +cloud-neoforge = { group = "org.incendo", name = "cloud-neoforge", version.ref = "cloud" } +minotaur = { group = "com.modrinth.minotaur", name = "Minotaur", version.ref = "minotaur" } +mixin = { group = "org.spongepowered", name = "mixin", version.ref = "mixin" } +asm = { group = "org.ow2.asm", name = "asm-debug-all", version.ref = "asm" } +minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft-version" } + +# Fabric +fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabric-loader" } +fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" } + +# NeoForge +neoforge = { group = "net.neoforged", name = "neoforge", version.ref = "neoforge-version" } + +[plugins] +lombok = { id = "io.freefair.lombok", version.ref = "lombok" } +blossom = { id = "net.kyori.blossom", version.ref = "blossom"} +indra = { id = "net.kyori.indra", version.ref = "indra" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180..e644113 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 48c0a02..a441313 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index c53aefa..1aa94a4 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -32,10 +32,10 @@ # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: # * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». # # Important for patching: # @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# 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 # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ @@ -205,6 +214,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index ac1b06f..7101f8e 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +41,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/mod/build.gradle.kts b/mod/build.gradle.kts new file mode 100644 index 0000000..3d990ac --- /dev/null +++ b/mod/build.gradle.kts @@ -0,0 +1,33 @@ +architectury { + common("neoforge", "fabric") +} + +loom { + accessWidenerPath = file("src/main/resources/floodgate.accesswidener") + mixin.defaultRefmapName.set("floodgate-refmap.json") +} + +dependencies { + api(libs.floodgate.core) + api(libs.floodgate.api) + api(libs.guice) + + compileOnly(libs.mixin) + compileOnly(libs.asm) + modCompileOnly(libs.geyser.mod) { isTransitive = false } + modCompileOnly(libs.geyser.core) { isTransitive = false } + + // Only here to suppress "unknown enum constant EnvType.CLIENT" warnings. + compileOnly(libs.fabric.loader) +} + +afterEvaluate { + // We don't need these + tasks.named("remapModrinthJar").configure { + enabled = false + } + + tasks.named("modrinth").configure { + enabled = false + } +} \ No newline at end of file diff --git a/mod/src/main/java/org/geysermc/floodgate/mod/FloodgateMod.java b/mod/src/main/java/org/geysermc/floodgate/mod/FloodgateMod.java new file mode 100644 index 0000000..b765b4f --- /dev/null +++ b/mod/src/main/java/org/geysermc/floodgate/mod/FloodgateMod.java @@ -0,0 +1,59 @@ +package org.geysermc.floodgate.mod; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Module; +import net.minecraft.server.MinecraftServer; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.floodgate.api.logger.FloodgateLogger; +import org.geysermc.floodgate.core.FloodgatePlatform; +import org.geysermc.floodgate.mod.module.ModAddonModule; +import org.geysermc.floodgate.mod.module.ModListenerModule; + +import java.nio.file.Path; + +public abstract class FloodgateMod { + public static FloodgateMod INSTANCE; + + private boolean started; + private FloodgatePlatform platform; + protected Injector injector; + + protected void init(Module... modules) { + INSTANCE = this; + injector = Guice.createInjector(modules); + platform = injector.getInstance(FloodgatePlatform.class); + } + + protected void enable(MinecraftServer server) { + long ctm = System.currentTimeMillis(); + + // Stupid hack, see the class for more information + // This can probably be Guice-i-fied but that is beyond me + MinecraftServerHolder.set(server); + + if (!started) { + platform.enable( + new ModAddonModule(), + new ModListenerModule() + ); + started = true; + } + + long endCtm = System.currentTimeMillis(); + injector.getInstance(FloodgateLogger.class) + .translatedInfo("floodgate.core.finish", endCtm - ctm); + } + + protected void disable() { + platform.disable(); + } + + protected void enable(Module... module) { + platform.enable(module); + } + + public @Nullable abstract Path resourcePath(String file); + + public abstract boolean isClient(); +} diff --git a/src/main/java/org/geysermc/floodgate/MinecraftServerHolder.java b/mod/src/main/java/org/geysermc/floodgate/mod/MinecraftServerHolder.java similarity index 92% rename from src/main/java/org/geysermc/floodgate/MinecraftServerHolder.java rename to mod/src/main/java/org/geysermc/floodgate/mod/MinecraftServerHolder.java index b1f0c9e..85be6d2 100644 --- a/src/main/java/org/geysermc/floodgate/MinecraftServerHolder.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/MinecraftServerHolder.java @@ -1,4 +1,4 @@ -package org.geysermc.floodgate; +package org.geysermc.floodgate.mod; import net.minecraft.server.MinecraftServer; diff --git a/src/main/java/org/geysermc/floodgate/addon/data/FabricDataAddon.java b/mod/src/main/java/org/geysermc/floodgate/mod/data/ModDataAddon.java similarity index 78% rename from src/main/java/org/geysermc/floodgate/addon/data/FabricDataAddon.java rename to mod/src/main/java/org/geysermc/floodgate/mod/data/ModDataAddon.java index ca93aae..6f0bb8e 100644 --- a/src/main/java/org/geysermc/floodgate/addon/data/FabricDataAddon.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/data/ModDataAddon.java @@ -1,18 +1,18 @@ -package org.geysermc.floodgate.addon.data; +package org.geysermc.floodgate.mod.data; import com.google.inject.Inject; import com.google.inject.name.Named; import io.netty.channel.Channel; import io.netty.util.AttributeKey; -import org.geysermc.floodgate.api.SimpleFloodgateApi; import org.geysermc.floodgate.api.inject.InjectorAddon; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; -import org.geysermc.floodgate.config.FloodgateConfig; -import org.geysermc.floodgate.player.FloodgateHandshakeHandler; -import org.geysermc.floodgate.util.Utils; +import org.geysermc.floodgate.core.api.SimpleFloodgateApi; +import org.geysermc.floodgate.core.config.FloodgateConfig; +import org.geysermc.floodgate.core.player.FloodgateHandshakeHandler; +import org.geysermc.floodgate.core.util.Utils; -public final class FabricDataAddon implements InjectorAddon { +public final class ModDataAddon implements InjectorAddon { @Inject private FloodgateHandshakeHandler handshakeHandler; @Inject private FloodgateConfig config; @Inject private SimpleFloodgateApi api; @@ -34,7 +34,7 @@ public final class FabricDataAddon implements InjectorAddon { public void onInject(Channel channel, boolean toServer) { channel.pipeline().addBefore( packetHandlerName, "floodgate_data_handler", - new FabricDataHandler(handshakeHandler, config, kickMessageAttribute, logger) + new ModDataHandler(handshakeHandler, config, kickMessageAttribute, logger) ); } diff --git a/src/main/java/org/geysermc/floodgate/addon/data/FabricDataHandler.java b/mod/src/main/java/org/geysermc/floodgate/mod/data/ModDataHandler.java similarity index 89% rename from src/main/java/org/geysermc/floodgate/addon/data/FabricDataHandler.java rename to mod/src/main/java/org/geysermc/floodgate/mod/data/ModDataHandler.java index eaced77..30590df 100644 --- a/src/main/java/org/geysermc/floodgate/addon/data/FabricDataHandler.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/data/ModDataHandler.java @@ -1,8 +1,10 @@ -package org.geysermc.floodgate.addon.data; +package org.geysermc.floodgate.mod.data; +import com.mojang.authlib.GameProfile; import com.mojang.authlib.minecraft.MinecraftSessionService; import com.mojang.logging.LogUtils; import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; import io.netty.util.AttributeKey; import net.minecraft.DefaultUncaughtExceptionHandler; import net.minecraft.network.Connection; @@ -10,28 +12,28 @@ import net.minecraft.network.protocol.handshake.ClientIntentionPacket; import net.minecraft.network.protocol.login.ServerboundHelloPacket; import net.minecraft.server.network.ServerLoginPacketListenerImpl; -import org.geysermc.floodgate.MinecraftServerHolder; import org.geysermc.floodgate.api.logger.FloodgateLogger; -import org.geysermc.floodgate.mixin.ConnectionMixin; -import org.geysermc.floodgate.mixin.ClientIntentionPacketMixinInterface; -import com.mojang.authlib.GameProfile; -import io.netty.channel.ChannelHandlerContext; import org.geysermc.floodgate.api.player.FloodgatePlayer; -import org.geysermc.floodgate.config.FloodgateConfig; -import org.geysermc.floodgate.player.FloodgateHandshakeHandler; -import org.geysermc.floodgate.player.FloodgateHandshakeHandler.HandshakeResult; +import org.geysermc.floodgate.core.addon.data.CommonDataHandler; +import org.geysermc.floodgate.core.addon.data.PacketBlocker; +import org.geysermc.floodgate.core.config.FloodgateConfig; +import org.geysermc.floodgate.core.player.FloodgateHandshakeHandler; +import org.geysermc.floodgate.core.player.FloodgateHandshakeHandler.HandshakeResult; +import org.geysermc.floodgate.mod.MinecraftServerHolder; +import org.geysermc.floodgate.mod.mixin.ClientIntentionPacketMixinInterface; +import org.geysermc.floodgate.mod.mixin.ConnectionMixin; import org.slf4j.Logger; import java.net.InetSocketAddress; -public final class FabricDataHandler extends CommonDataHandler { +public final class ModDataHandler extends CommonDataHandler { private static final Logger LOGGER = LogUtils.getLogger(); private final FloodgateLogger logger; private Connection networkManager; private FloodgatePlayer player; - public FabricDataHandler( + public ModDataHandler( FloodgateHandshakeHandler handshakeHandler, FloodgateConfig config, AttributeKey kickMessageAttribute, FloodgateLogger logger) { diff --git a/src/main/java/org/geysermc/floodgate/inject/fabric/FabricInjector.java b/mod/src/main/java/org/geysermc/floodgate/mod/inject/ModInjector.java similarity index 78% rename from src/main/java/org/geysermc/floodgate/inject/fabric/FabricInjector.java rename to mod/src/main/java/org/geysermc/floodgate/mod/inject/ModInjector.java index 15f0a1a..dcd2d23 100644 --- a/src/main/java/org/geysermc/floodgate/inject/fabric/FabricInjector.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/inject/ModInjector.java @@ -1,19 +1,21 @@ -package org.geysermc.floodgate.inject.fabric; +package org.geysermc.floodgate.mod.inject; import com.google.inject.Inject; -import io.netty.channel.*; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInitializer; import lombok.Getter; import lombok.RequiredArgsConstructor; -import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.floodgate.api.logger.FloodgateLogger; -import org.geysermc.floodgate.inject.CommonPlatformInjector; +import org.geysermc.floodgate.core.inject.CommonPlatformInjector; @RequiredArgsConstructor -public final class FabricInjector extends CommonPlatformInjector { +public final class ModInjector extends CommonPlatformInjector { - @Setter @Getter - private static FabricInjector instance; + public static ModInjector INSTANCE = new ModInjector(); @Getter private final boolean injected = true; diff --git a/src/main/java/org/geysermc/floodgate/listener/FabricEventListener.java b/mod/src/main/java/org/geysermc/floodgate/mod/listener/ModEventListener.java similarity index 55% rename from src/main/java/org/geysermc/floodgate/listener/FabricEventListener.java rename to mod/src/main/java/org/geysermc/floodgate/mod/listener/ModEventListener.java index b94e1d3..6f116e3 100644 --- a/src/main/java/org/geysermc/floodgate/listener/FabricEventListener.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/listener/ModEventListener.java @@ -1,21 +1,20 @@ -package org.geysermc.floodgate.listener; +package org.geysermc.floodgate.mod.listener; import com.google.inject.Inject; -import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerGamePacketListenerImpl; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.player.FloodgatePlayer; -import org.geysermc.floodgate.util.LanguageManager; +import org.geysermc.floodgate.core.util.LanguageManager; -public final class FabricEventListener { +import java.util.UUID; + +public final class ModEventListener { @Inject private FloodgateApi api; @Inject private FloodgateLogger logger; @Inject private LanguageManager languageManager; - public void onPlayerJoin(ServerGamePacketListenerImpl networkHandler, PacketSender packetSender, MinecraftServer server) { - FloodgatePlayer player = api.getPlayer(networkHandler.player.getUUID()); + public void onPlayerJoin(UUID uuid) { + FloodgatePlayer player = api.getPlayer(uuid); if (player != null) { logger.translatedInfo( "floodgate.ingame.login_name", diff --git a/src/main/java/org/geysermc/floodgate/logger/Log4jFloodgateLogger.java b/mod/src/main/java/org/geysermc/floodgate/mod/logger/Log4jFloodgateLogger.java similarity index 88% rename from src/main/java/org/geysermc/floodgate/logger/Log4jFloodgateLogger.java rename to mod/src/main/java/org/geysermc/floodgate/mod/logger/Log4jFloodgateLogger.java index d24223f..b3eb481 100644 --- a/src/main/java/org/geysermc/floodgate/logger/Log4jFloodgateLogger.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/logger/Log4jFloodgateLogger.java @@ -1,4 +1,4 @@ -package org.geysermc.floodgate.logger; +package org.geysermc.floodgate.mod.logger; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -7,10 +7,10 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.core.config.Configurator; import org.geysermc.floodgate.api.logger.FloodgateLogger; -import org.geysermc.floodgate.config.FloodgateConfig; -import org.geysermc.floodgate.util.LanguageManager; +import org.geysermc.floodgate.core.config.FloodgateConfig; +import org.geysermc.floodgate.core.util.LanguageManager; -import static org.geysermc.floodgate.util.MessageFormatter.format; +import static org.geysermc.floodgate.core.util.MessageFormatter.format; @Singleton public final class Log4jFloodgateLogger implements FloodgateLogger { diff --git a/src/main/java/org/geysermc/floodgate/mixin/ChunkMapMixin.java b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/ChunkMapMixin.java similarity index 88% rename from src/main/java/org/geysermc/floodgate/mixin/ChunkMapMixin.java rename to mod/src/main/java/org/geysermc/floodgate/mod/mixin/ChunkMapMixin.java index 3805dbb..c959ebf 100644 --- a/src/main/java/org/geysermc/floodgate/mixin/ChunkMapMixin.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/ChunkMapMixin.java @@ -1,4 +1,4 @@ -package org.geysermc.floodgate.mixin; +package org.geysermc.floodgate.mod.mixin; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.server.level.ChunkMap; diff --git a/src/main/java/org/geysermc/floodgate/mixin/ClientIntentionPacketMixin.java b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/ClientIntentionPacketMixin.java similarity index 92% rename from src/main/java/org/geysermc/floodgate/mixin/ClientIntentionPacketMixin.java rename to mod/src/main/java/org/geysermc/floodgate/mod/mixin/ClientIntentionPacketMixin.java index e8c0dbf..75b5df4 100644 --- a/src/main/java/org/geysermc/floodgate/mixin/ClientIntentionPacketMixin.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/ClientIntentionPacketMixin.java @@ -1,4 +1,4 @@ -package org.geysermc.floodgate.mixin; +package org.geysermc.floodgate.mod.mixin; import net.minecraft.network.protocol.handshake.ClientIntentionPacket; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/org/geysermc/floodgate/mixin/ClientIntentionPacketMixinInterface.java b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/ClientIntentionPacketMixinInterface.java similarity index 90% rename from src/main/java/org/geysermc/floodgate/mixin/ClientIntentionPacketMixinInterface.java rename to mod/src/main/java/org/geysermc/floodgate/mod/mixin/ClientIntentionPacketMixinInterface.java index 8ffdcba..ee06792 100644 --- a/src/main/java/org/geysermc/floodgate/mixin/ClientIntentionPacketMixinInterface.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/ClientIntentionPacketMixinInterface.java @@ -1,4 +1,4 @@ -package org.geysermc.floodgate.mixin; +package org.geysermc.floodgate.mod.mixin; import net.minecraft.network.protocol.handshake.ClientIntentionPacket; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/java/org/geysermc/floodgate/mixin/ConnectionMixin.java b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/ConnectionMixin.java similarity index 87% rename from src/main/java/org/geysermc/floodgate/mixin/ConnectionMixin.java rename to mod/src/main/java/org/geysermc/floodgate/mod/mixin/ConnectionMixin.java index 6494822..e085cd3 100644 --- a/src/main/java/org/geysermc/floodgate/mixin/ConnectionMixin.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/ConnectionMixin.java @@ -1,4 +1,4 @@ -package org.geysermc.floodgate.mixin; +package org.geysermc.floodgate.mod.mixin; import net.minecraft.network.Connection; import org.spongepowered.asm.mixin.Mixin; diff --git a/mod/src/main/java/org/geysermc/floodgate/mod/mixin/FloodgateUtilMixin.java b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/FloodgateUtilMixin.java new file mode 100644 index 0000000..e654b7c --- /dev/null +++ b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/FloodgateUtilMixin.java @@ -0,0 +1,49 @@ +package org.geysermc.floodgate.mod.mixin; + +import org.geysermc.floodgate.core.util.Utils; +import org.geysermc.floodgate.mod.FloodgateMod; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * Mixins into Floodgate's {@link Utils} class to modify how resources are loaded from the jar. + * This must be done due to mod platforms sharing a classloader across mods - this leads to Floodgate + * loading Geyser's language files, as they're not prefixed to avoid conflicts. + * To resolve this, this mixin replaces those calls with the platform-appropriate methods to load files. + */ +@Mixin(value = Utils.class, remap = false) +public class FloodgateUtilMixin { + + @Redirect(method = "readProperties", + at = @At(value = "INVOKE", target = "Ljava/lang/ClassLoader;getResourceAsStream(Ljava/lang/String;)Ljava/io/InputStream;")) + private static InputStream floodgate$redirectInputStream(ClassLoader instance, String string) { + Path path = FloodgateMod.INSTANCE.resourcePath(string); + try { + return path == null ? null : Files.newInputStream(path); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Redirect(method = "getGeneratedClassesForAnnotation(Ljava/lang/String;)Ljava/util/Set;", + at = @At(value = "INVOKE", target = "Ljava/lang/ClassLoader;getResourceAsStream(Ljava/lang/String;)Ljava/io/InputStream;")) + private static InputStream floodgate$redirectInputStreamAnnotation(ClassLoader instance, String string) { + Path path = FloodgateMod.INSTANCE.resourcePath(string); + + if (path == null) { + throw new IllegalStateException("Unable to find annotation class! " + string); + } + + try { + return Files.newInputStream(path); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/org/geysermc/floodgate/mixin/GeyserModInjectorMixin.java b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/GeyserModInjectorMixin.java similarity index 71% rename from src/main/java/org/geysermc/floodgate/mixin/GeyserModInjectorMixin.java rename to mod/src/main/java/org/geysermc/floodgate/mod/mixin/GeyserModInjectorMixin.java index 4b117ad..39ab73d 100644 --- a/src/main/java/org/geysermc/floodgate/mixin/GeyserModInjectorMixin.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/GeyserModInjectorMixin.java @@ -1,7 +1,7 @@ -package org.geysermc.floodgate.mixin; +package org.geysermc.floodgate.mod.mixin; import io.netty.channel.ChannelFuture; -import org.geysermc.floodgate.inject.fabric.FabricInjector; +import org.geysermc.floodgate.mod.inject.ModInjector; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.platform.mod.GeyserModInjector; import org.spongepowered.asm.mixin.Mixin; @@ -19,7 +19,7 @@ public class GeyserModInjectorMixin { private List allServerChannels; @Inject(method = "initializeLocalChannel0", at = @At(value = "INVOKE_ASSIGN", target = "Ljava/util/List;add(Ljava/lang/Object;)Z")) - public void onChannelAdd(GeyserBootstrap bootstrap, CallbackInfo ci) { - FabricInjector.getInstance().injectClient(this.allServerChannels.get(this.allServerChannels.size() - 1)); + public void floodgate$onChannelAdd(GeyserBootstrap bootstrap, CallbackInfo ci) { + ModInjector.INSTANCE.injectClient(this.allServerChannels.get(this.allServerChannels.size() - 1)); } } diff --git a/src/main/java/org/geysermc/floodgate/mixin/ServerConnectionListenerMixin.java b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/ServerConnectionListenerMixin.java similarity index 73% rename from src/main/java/org/geysermc/floodgate/mixin/ServerConnectionListenerMixin.java rename to mod/src/main/java/org/geysermc/floodgate/mod/mixin/ServerConnectionListenerMixin.java index dd04e51..e094da2 100644 --- a/src/main/java/org/geysermc/floodgate/mixin/ServerConnectionListenerMixin.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/mixin/ServerConnectionListenerMixin.java @@ -1,8 +1,8 @@ -package org.geysermc.floodgate.mixin; +package org.geysermc.floodgate.mod.mixin; -import net.minecraft.server.network.ServerConnectionListener; -import org.geysermc.floodgate.inject.fabric.FabricInjector; import io.netty.channel.ChannelFuture; +import net.minecraft.server.network.ServerConnectionListener; +import org.geysermc.floodgate.mod.inject.ModInjector; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -19,7 +19,7 @@ public abstract class ServerConnectionListenerMixin { @Shadow @Final private List channels; @Inject(method = "startTcpServerListener", at = @At(value = "INVOKE_ASSIGN", target = "Ljava/util/List;add(Ljava/lang/Object;)Z")) - public void onChannelAdd(InetAddress address, int port, CallbackInfo ci) { - FabricInjector.getInstance().injectClient(this.channels.get(this.channels.size() - 1)); + public void floodgate$onChannelAdd(InetAddress address, int port, CallbackInfo ci) { + ModInjector.INSTANCE.injectClient(this.channels.get(this.channels.size() - 1)); } } diff --git a/src/main/java/org/geysermc/floodgate/module/FabricAddonModule.java b/mod/src/main/java/org/geysermc/floodgate/mod/module/ModAddonModule.java similarity index 63% rename from src/main/java/org/geysermc/floodgate/module/FabricAddonModule.java rename to mod/src/main/java/org/geysermc/floodgate/mod/module/ModAddonModule.java index 2dd731c..fdd9f57 100644 --- a/src/main/java/org/geysermc/floodgate/module/FabricAddonModule.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/module/ModAddonModule.java @@ -1,15 +1,15 @@ -package org.geysermc.floodgate.module; +package org.geysermc.floodgate.mod.module; -import org.geysermc.floodgate.addon.data.FabricDataAddon; import com.google.inject.AbstractModule; import com.google.inject.Singleton; import com.google.inject.multibindings.ProvidesIntoSet; -import org.geysermc.floodgate.addon.AddonManagerAddon; -import org.geysermc.floodgate.addon.DebugAddon; import org.geysermc.floodgate.api.inject.InjectorAddon; -import org.geysermc.floodgate.register.AddonRegister; +import org.geysermc.floodgate.core.addon.AddonManagerAddon; +import org.geysermc.floodgate.core.addon.DebugAddon; +import org.geysermc.floodgate.core.register.AddonRegister; +import org.geysermc.floodgate.mod.data.ModDataAddon; -public final class FabricAddonModule extends AbstractModule { +public final class ModAddonModule extends AbstractModule { @Override protected void configure() { bind(AddonRegister.class).asEagerSingleton(); @@ -24,7 +24,7 @@ public InjectorAddon managerAddon() { @Singleton @ProvidesIntoSet public InjectorAddon dataAddon() { - return new FabricDataAddon(); + return new ModDataAddon(); } @Singleton diff --git a/mod/src/main/java/org/geysermc/floodgate/mod/module/ModListenerModule.java b/mod/src/main/java/org/geysermc/floodgate/mod/module/ModListenerModule.java new file mode 100644 index 0000000..98d4532 --- /dev/null +++ b/mod/src/main/java/org/geysermc/floodgate/mod/module/ModListenerModule.java @@ -0,0 +1,21 @@ +package org.geysermc.floodgate.mod.module; + +import com.google.inject.AbstractModule; +import com.google.inject.Singleton; +import com.google.inject.TypeLiteral; +import com.google.inject.multibindings.ProvidesIntoSet; +import org.geysermc.floodgate.core.register.ListenerRegister; +import org.geysermc.floodgate.mod.listener.ModEventListener; + +public final class ModListenerModule extends AbstractModule { + @Override + protected void configure() { + bind(new TypeLiteral>() {}).asEagerSingleton(); + } + + @Singleton + @ProvidesIntoSet + public ModEventListener modEventListener() { + return new ModEventListener(); + } +} diff --git a/mod/src/main/java/org/geysermc/floodgate/mod/module/ModPlatformModule.java b/mod/src/main/java/org/geysermc/floodgate/mod/module/ModPlatformModule.java new file mode 100644 index 0000000..534849a --- /dev/null +++ b/mod/src/main/java/org/geysermc/floodgate/mod/module/ModPlatformModule.java @@ -0,0 +1,77 @@ +package org.geysermc.floodgate.mod.module; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.Singleton; +import com.google.inject.name.Named; +import com.google.inject.name.Names; +import lombok.RequiredArgsConstructor; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.geysermc.floodgate.api.FloodgateApi; +import org.geysermc.floodgate.api.logger.FloodgateLogger; +import org.geysermc.floodgate.core.inject.CommonPlatformInjector; +import org.geysermc.floodgate.core.platform.command.CommandUtil; +import org.geysermc.floodgate.core.platform.util.PlatformUtils; +import org.geysermc.floodgate.core.skin.SkinApplier; +import org.geysermc.floodgate.core.util.LanguageManager; +import org.geysermc.floodgate.mod.FloodgateMod; +import org.geysermc.floodgate.mod.inject.ModInjector; +import org.geysermc.floodgate.mod.logger.Log4jFloodgateLogger; +import org.geysermc.floodgate.mod.pluginmessage.ModSkinApplier; +import org.geysermc.floodgate.mod.util.ModCommandUtil; +import org.geysermc.floodgate.mod.util.ModPlatformUtils; + +@RequiredArgsConstructor +public abstract class ModPlatformModule extends AbstractModule { + + @Provides + @Singleton + public CommandUtil commandUtil( + FloodgateApi api, + FloodgateLogger logger, + LanguageManager languageManager) { + return new ModCommandUtil(languageManager, api, logger); + } + + @Override + protected void configure() { + bind(PlatformUtils.class).to(ModPlatformUtils.class); + bind(Logger.class).annotatedWith(Names.named("logger")).toInstance(LogManager.getLogger("floodgate")); + bind(FloodgateLogger.class).to(Log4jFloodgateLogger.class); + } + + /* + DebugAddon / PlatformInjector + */ + + @Provides + @Singleton + public CommonPlatformInjector platformInjector() { + return ModInjector.INSTANCE; + } + + @Provides + @Named("packetEncoder") + public String packetEncoder() { + return FloodgateMod.INSTANCE.isClient() ? "encoder" : "outbound_config"; + } + + @Provides + @Named("packetDecoder") + public String packetDecoder() { + return FloodgateMod.INSTANCE.isClient() ? "inbound_config" : "decoder" ; + } + + @Provides + @Named("packetHandler") + public String packetHandler() { + return "packet_handler"; + } + + @Provides + @Singleton + public SkinApplier skinApplier() { + return new ModSkinApplier(); + } +} diff --git a/src/main/java/org/geysermc/floodgate/pluginmessage/FabricSkinApplier.java b/mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/ModSkinApplier.java similarity index 90% rename from src/main/java/org/geysermc/floodgate/pluginmessage/FabricSkinApplier.java rename to mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/ModSkinApplier.java index 374c2d8..4537172 100644 --- a/src/main/java/org/geysermc/floodgate/pluginmessage/FabricSkinApplier.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/ModSkinApplier.java @@ -1,4 +1,4 @@ -package org.geysermc.floodgate.pluginmessage; +package org.geysermc.floodgate.mod.pluginmessage; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; @@ -8,16 +8,16 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.floodgate.MinecraftServerHolder; import org.geysermc.floodgate.api.player.FloodgatePlayer; -import org.geysermc.floodgate.mixin.ChunkMapMixin; -import org.geysermc.floodgate.skin.SkinApplier; - -import static org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData; +import org.geysermc.floodgate.core.skin.SkinApplier; +import org.geysermc.floodgate.mod.MinecraftServerHolder; +import org.geysermc.floodgate.mod.mixin.ChunkMapMixin; import java.util.Collections; -public final class FabricSkinApplier implements SkinApplier { +import static org.geysermc.floodgate.api.event.skin.SkinApplyEvent.SkinData; + +public final class ModSkinApplier implements SkinApplier { @Override public void applySkin(@NonNull FloodgatePlayer floodgatePlayer, @NonNull SkinData skinData) { diff --git a/src/main/java/org/geysermc/floodgate/pluginmessage/payloads/FormPayload.java b/mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/payloads/FormPayload.java similarity index 94% rename from src/main/java/org/geysermc/floodgate/pluginmessage/payloads/FormPayload.java rename to mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/payloads/FormPayload.java index 475d138..fa7b727 100644 --- a/src/main/java/org/geysermc/floodgate/pluginmessage/payloads/FormPayload.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/payloads/FormPayload.java @@ -1,4 +1,4 @@ -package org.geysermc.floodgate.pluginmessage.payloads; +package org.geysermc.floodgate.mod.pluginmessage.payloads; import io.netty.buffer.ByteBufUtil; import net.minecraft.network.FriendlyByteBuf; diff --git a/src/main/java/org/geysermc/floodgate/pluginmessage/payloads/PacketPayload.java b/mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/payloads/PacketPayload.java similarity index 94% rename from src/main/java/org/geysermc/floodgate/pluginmessage/payloads/PacketPayload.java rename to mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/payloads/PacketPayload.java index b00021b..944ea86 100644 --- a/src/main/java/org/geysermc/floodgate/pluginmessage/payloads/PacketPayload.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/payloads/PacketPayload.java @@ -1,4 +1,4 @@ -package org.geysermc.floodgate.pluginmessage.payloads; +package org.geysermc.floodgate.mod.pluginmessage.payloads; import io.netty.buffer.ByteBufUtil; import net.minecraft.network.FriendlyByteBuf; diff --git a/src/main/java/org/geysermc/floodgate/pluginmessage/payloads/SkinPayload.java b/mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/payloads/SkinPayload.java similarity index 94% rename from src/main/java/org/geysermc/floodgate/pluginmessage/payloads/SkinPayload.java rename to mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/payloads/SkinPayload.java index a1e6eee..16fda96 100644 --- a/src/main/java/org/geysermc/floodgate/pluginmessage/payloads/SkinPayload.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/payloads/SkinPayload.java @@ -1,4 +1,4 @@ -package org.geysermc.floodgate.pluginmessage.payloads; +package org.geysermc.floodgate.mod.pluginmessage.payloads; import io.netty.buffer.ByteBufUtil; import net.minecraft.network.FriendlyByteBuf; diff --git a/src/main/java/org/geysermc/floodgate/pluginmessage/payloads/TransferPayload.java b/mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/payloads/TransferPayload.java similarity index 94% rename from src/main/java/org/geysermc/floodgate/pluginmessage/payloads/TransferPayload.java rename to mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/payloads/TransferPayload.java index 6396327..597634e 100644 --- a/src/main/java/org/geysermc/floodgate/pluginmessage/payloads/TransferPayload.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/pluginmessage/payloads/TransferPayload.java @@ -1,4 +1,4 @@ -package org.geysermc.floodgate.pluginmessage.payloads; +package org.geysermc.floodgate.mod.pluginmessage.payloads; import io.netty.buffer.ByteBufUtil; import net.minecraft.network.FriendlyByteBuf; diff --git a/src/main/java/org/geysermc/floodgate/util/FabricCommandUtil.java b/mod/src/main/java/org/geysermc/floodgate/mod/util/ModCommandUtil.java similarity index 82% rename from src/main/java/org/geysermc/floodgate/util/FabricCommandUtil.java rename to mod/src/main/java/org/geysermc/floodgate/mod/util/ModCommandUtil.java index 0382148..c5685d2 100644 --- a/src/main/java/org/geysermc/floodgate/util/FabricCommandUtil.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/util/ModCommandUtil.java @@ -1,28 +1,30 @@ -package org.geysermc.floodgate.util; +package org.geysermc.floodgate.mod.util; import com.mojang.authlib.GameProfile; -import me.lucko.fabric.api.permissions.v0.Permissions; -import net.minecraft.commands.CommandSource; +import lombok.Setter; import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.players.UserWhiteListEntry; import org.checkerframework.checker.nullness.qual.NonNull; -import org.geysermc.floodgate.MinecraftServerHolder; import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.logger.FloodgateLogger; -import org.geysermc.floodgate.platform.command.CommandUtil; -import org.geysermc.floodgate.player.UserAudience; +import org.geysermc.floodgate.core.platform.command.CommandUtil; +import org.geysermc.floodgate.core.player.UserAudience; +import org.geysermc.floodgate.core.util.LanguageManager; +import org.geysermc.floodgate.mod.MinecraftServerHolder; +import org.incendo.cloud.CommandManager; -import java.util.*; -import java.util.logging.Logger; +import java.util.Collection; +import java.util.UUID; -public final class FabricCommandUtil extends CommandUtil { +public final class ModCommandUtil extends CommandUtil { private final FloodgateLogger logger; private UserAudience console; + @Setter + private CommandManager commandManager; - public FabricCommandUtil(LanguageManager manager, FloodgateApi api, FloodgateLogger logger) { + public ModCommandUtil(LanguageManager manager, FloodgateApi api, FloodgateLogger logger) { super(manager, api); this.logger = logger; } @@ -73,8 +75,7 @@ protected Collection getOnlinePlayers() { @Override public boolean hasPermission(Object source, String permission) { - return Permissions.check((SharedSuggestionProvider) source, - permission, MinecraftServerHolder.get().getOperatorUserPermissionLevel()); + return commandManager.hasPermission(getUserAudience(source), permission); } @Override diff --git a/src/main/java/org/geysermc/floodgate/util/MixinConfigPlugin.java b/mod/src/main/java/org/geysermc/floodgate/mod/util/ModMixinConfigPlugin.java similarity index 56% rename from src/main/java/org/geysermc/floodgate/util/MixinConfigPlugin.java rename to mod/src/main/java/org/geysermc/floodgate/mod/util/ModMixinConfigPlugin.java index b8ee162..47945b7 100644 --- a/src/main/java/org/geysermc/floodgate/util/MixinConfigPlugin.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/util/ModMixinConfigPlugin.java @@ -1,6 +1,6 @@ -package org.geysermc.floodgate.util; +package org.geysermc.floodgate.mod.util; -import net.fabricmc.loader.api.FabricLoader; +import dev.architectury.injectables.annotations.ExpectPlatform; import org.objectweb.asm.tree.ClassNode; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; @@ -8,7 +8,7 @@ import java.util.List; import java.util.Set; -public class MixinConfigPlugin implements IMixinConfigPlugin { +public class ModMixinConfigPlugin implements IMixinConfigPlugin { @Override public void onLoad(String mixinPackage) { @@ -21,12 +21,11 @@ public String getRefMapperConfig() { @Override public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { - if (mixinClassName.equals("org.geysermc.floodgate.mixin.ClientIntentionPacketMixin")) { - //returns true if fabricproxy-lite is present, therefore loading the mixin. If not present, the mixin will not be loaded. - return FabricLoader.getInstance().isModLoaded("fabricproxy-lite"); + if (mixinClassName.equals("org.geysermc.floodgate.mod.mixin.ClientIntentionPacketMixin")) { + return applyProxyFix(); } - if (mixinClassName.equals("org.geysermc.floodgate.mixin.GeyserModInjectorMixin")) { - return FabricLoader.getInstance().isModLoaded("geyser-fabric"); + if (mixinClassName.equals("org.geysermc.floodgate.mod.mixin.GeyserModInjectorMixin")) { + return isGeyserLoaded(); } return true; } @@ -47,4 +46,14 @@ public void preApply(String targetClassName, ClassNode targetClass, String mixin @Override public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { } + + @ExpectPlatform + public static boolean isGeyserLoaded() { + throw new IllegalStateException("isGeyserLoaded is not implemented!"); + } + + @ExpectPlatform + public static boolean applyProxyFix() { + throw new IllegalStateException("applyProxyFix is not implemented!"); + } } \ No newline at end of file diff --git a/src/main/java/org/geysermc/floodgate/util/FabricPlatformUtils.java b/mod/src/main/java/org/geysermc/floodgate/mod/util/ModPlatformUtils.java similarity index 67% rename from src/main/java/org/geysermc/floodgate/util/FabricPlatformUtils.java rename to mod/src/main/java/org/geysermc/floodgate/mod/util/ModPlatformUtils.java index 900ec2d..6ab2dfd 100644 --- a/src/main/java/org/geysermc/floodgate/util/FabricPlatformUtils.java +++ b/mod/src/main/java/org/geysermc/floodgate/mod/util/ModPlatformUtils.java @@ -1,10 +1,10 @@ -package org.geysermc.floodgate.util; +package org.geysermc.floodgate.mod.util; import net.minecraft.SharedConstants; -import org.geysermc.floodgate.MinecraftServerHolder; -import org.geysermc.floodgate.platform.util.PlatformUtils; +import org.geysermc.floodgate.core.platform.util.PlatformUtils; +import org.geysermc.floodgate.mod.MinecraftServerHolder; -public class FabricPlatformUtils extends PlatformUtils { +public class ModPlatformUtils extends PlatformUtils { @Override public AuthType authType() { return MinecraftServerHolder.get().usesAuthentication() ? AuthType.ONLINE : AuthType.OFFLINE; diff --git a/mod/src/main/java/org/geysermc/floodgate/mod/util/ModTemplateReader.java b/mod/src/main/java/org/geysermc/floodgate/mod/util/ModTemplateReader.java new file mode 100644 index 0000000..9f0d4df --- /dev/null +++ b/mod/src/main/java/org/geysermc/floodgate/mod/util/ModTemplateReader.java @@ -0,0 +1,25 @@ +package org.geysermc.floodgate.mod.util; + +import org.geysermc.configutils.file.template.TemplateReader; +import org.geysermc.floodgate.mod.FloodgateMod; + +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class ModTemplateReader implements TemplateReader { + + @Override + public BufferedReader read(String configName) { + Path path = FloodgateMod.INSTANCE.resourcePath(configName); + if (path != null) { + try { + return Files.newBufferedReader(path); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + return null; + } +} diff --git a/src/main/resources/floodgate.accesswidener b/mod/src/main/resources/floodgate.accesswidener similarity index 100% rename from src/main/resources/floodgate.accesswidener rename to mod/src/main/resources/floodgate.accesswidener diff --git a/src/main/resources/floodgate.mixins.json b/mod/src/main/resources/floodgate.mixins.json similarity index 69% rename from src/main/resources/floodgate.mixins.json rename to mod/src/main/resources/floodgate.mixins.json index ca8e559..d3597fb 100644 --- a/src/main/resources/floodgate.mixins.json +++ b/mod/src/main/resources/floodgate.mixins.json @@ -1,17 +1,18 @@ { "required": true, "minVersion": "0.8", - "package": "org.geysermc.floodgate.mixin", + "package": "org.geysermc.floodgate.mod.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ "ChunkMapMixin", "ClientIntentionPacketMixin", "ClientIntentionPacketMixinInterface", "ConnectionMixin", + "FloodgateUtilMixin", "GeyserModInjectorMixin", "ServerConnectionListenerMixin" ], - "plugin": "org.geysermc.floodgate.util.MixinConfigPlugin", + "plugin": "org.geysermc.floodgate.mod.util.ModMixinConfigPlugin", "injectors": { "defaultRequire": 1 } diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts new file mode 100644 index 0000000..6f18ab5 --- /dev/null +++ b/neoforge/build.gradle.kts @@ -0,0 +1,61 @@ +architectury { + platformSetupLoomIde() + neoForge() +} + +provided("com.google.guava", "failureaccess") + +// Used to extend runtime/compile classpaths +val common: Configuration by configurations.creating +// Needed to read mixin config in the runServer task, and for the architectury transformer +// (e.g. the @ExpectPlatform annotation) +val developmentNeoForge: Configuration = configurations.getByName("developmentNeoForge") +// Our custom transitive include configuration +val includeTransitive: Configuration = configurations.getByName("includeTransitive") + +configurations { + compileClasspath.get().extendsFrom(configurations["common"]) + runtimeClasspath.get().extendsFrom(configurations["common"]) + developmentNeoForge.extendsFrom(configurations["common"]) +} + +dependencies { + // See https://github.com/google/guava/issues/6618 + modules { + module("com.google.guava:listenablefuture") { + replacedBy("com.google.guava:guava", "listenablefuture is part of guava") + } + } + + neoForge(libs.neoforge) + // "namedElements" configuration should be used to depend on different loom projects + common(project(":mod", configuration = "namedElements")) { isTransitive = false } + // Bundle transformed classes of the common module for production mod jar + shadow(project(path = ":mod", configuration = "transformProductionNeoForge")) { isTransitive = false } + + includeTransitive(libs.floodgate.core) + + implementation(libs.floodgate.core) + implementation(libs.guice) + + modImplementation(libs.cloud.neoforge) + include(libs.cloud.neoforge) +} + +tasks { + processResources { + from(project(":mod").file("src/main/resources/floodgate.accesswidener")) { + into("/assets/") + } + } + + remapJar { + dependsOn(processResources) + atAccessWideners.add("floodgate.accesswidener") + archiveBaseName.set("floodgate-neoforge") + } + + modrinth { + loaders.add("neoforge") + } +} diff --git a/neoforge/gradle.properties b/neoforge/gradle.properties new file mode 100644 index 0000000..2914393 --- /dev/null +++ b/neoforge/gradle.properties @@ -0,0 +1 @@ +loom.platform=neoforge \ No newline at end of file diff --git a/neoforge/src/main/java/org/geysermc/floodgate/mod/util/neoforge/ModMixinConfigPluginImpl.java b/neoforge/src/main/java/org/geysermc/floodgate/mod/util/neoforge/ModMixinConfigPluginImpl.java new file mode 100644 index 0000000..27159f6 --- /dev/null +++ b/neoforge/src/main/java/org/geysermc/floodgate/mod/util/neoforge/ModMixinConfigPluginImpl.java @@ -0,0 +1,13 @@ +package org.geysermc.floodgate.mod.util.neoforge; + +import net.neoforged.fml.loading.LoadingModList; + +public class ModMixinConfigPluginImpl { + public static boolean isGeyserLoaded() { + return LoadingModList.get().getModFileById("geyser_neoforge") != null; + } + + public static boolean applyProxyFix() { + return false; + } +} diff --git a/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/NeoForgeFloodgateMod.java b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/NeoForgeFloodgateMod.java new file mode 100644 index 0000000..e3d09d5 --- /dev/null +++ b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/NeoForgeFloodgateMod.java @@ -0,0 +1,101 @@ +package org.geysermc.floodgate.platform.neoforge; + +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.loading.FMLLoader; +import net.neoforged.fml.loading.FMLPaths; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.GameShuttingDownEvent; +import net.neoforged.neoforge.event.server.ServerStartedEvent; +import net.neoforged.neoforge.event.server.ServerStoppingEvent; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.floodgate.api.logger.FloodgateLogger; +import org.geysermc.floodgate.core.module.PluginMessageModule; +import org.geysermc.floodgate.core.module.ServerCommonModule; +import org.geysermc.floodgate.mod.FloodgateMod; +import org.geysermc.floodgate.mod.util.ModTemplateReader; +import org.geysermc.floodgate.platform.neoforge.module.NeoForgeCommandModule; +import org.geysermc.floodgate.platform.neoforge.module.NeoForgePlatformModule; +import org.geysermc.floodgate.platform.neoforge.pluginmessage.NeoForgePluginMessageRegistration; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.nio.file.Path; +import java.util.Set; +import java.util.stream.Collectors; + +@Mod("floodgate") +public final class NeoForgeFloodgateMod extends FloodgateMod { + + private final ModContainer container; + + public NeoForgeFloodgateMod(IEventBus modEventBus, ModContainer container) { + this.container = container; + init( + new ServerCommonModule( + FMLPaths.CONFIGDIR.get().resolve("floodgate"), + new ModTemplateReader() + ), + new NeoForgePlatformModule(), + new NeoForgeCommandModule() + ); + + modEventBus.addListener(this::onRegisterPackets); + NeoForge.EVENT_BUS.addListener(this::onServerStarted); + if (FMLLoader.getDist().isClient()) { + NeoForge.EVENT_BUS.addListener(this::onClientStop); + } else { + NeoForge.EVENT_BUS.addListener(this::onServerStop); + } + } + + private void onServerStarted(ServerStartedEvent event) { + this.enable(event.getServer()); + } + + private void onClientStop(GameShuttingDownEvent ignored) { + this.disable(); + } + + private void onServerStop(ServerStoppingEvent ignored) { + this.disable(); + } + + private void onRegisterPackets(final RegisterPayloadHandlersEvent event) { + // Set the registrar once we're given it - NeoForgePluginMessageRegistration was created earlier in NeoForgePlatformModule + NeoForgePluginMessageRegistration pluginMessageRegistration = injector.getInstance(NeoForgePluginMessageRegistration.class); + pluginMessageRegistration.setRegistrar(event.registrar("floodgate").optional()); + + // We can now trigger the registering of our plugin message channels + enable(new PluginMessageModule()); + } + + @Override + public @Nullable Path resourcePath(String file) { + return container.getModInfo().getOwningFile().getFile().findResource(file); + } + + @Override + public boolean isClient() { + return FMLLoader.getDist().isClient(); + } + + public Set> getAnnotatedClasses(Class annotationClass) { + return container.getModInfo() + .getOwningFile() + .getFile() + .getScanResult() + .getAnnotatedBy(annotationClass, ElementType.TYPE) + .map(annotationData -> { + try { + return Class.forName(annotationData.clazz().getClassName()); + } catch (Exception e) { + injector.getInstance(FloodgateLogger.class).error(e.getMessage(), e); + return null; + } + }) + .collect(Collectors.toSet()); + } +} diff --git a/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/listener/NeoForgeEventRegistration.java b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/listener/NeoForgeEventRegistration.java new file mode 100644 index 0000000..77afc91 --- /dev/null +++ b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/listener/NeoForgeEventRegistration.java @@ -0,0 +1,20 @@ +package org.geysermc.floodgate.platform.neoforge.listener; + +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import org.geysermc.floodgate.core.platform.listener.ListenerRegistration; +import org.geysermc.floodgate.mod.listener.ModEventListener; + +public final class NeoForgeEventRegistration implements ListenerRegistration { + private ModEventListener listener; + + @Override + public void register(ModEventListener listener) { + NeoForge.EVENT_BUS.addListener(this::onPlayerJoin); + this.listener = listener; + } + + private void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) { + listener.onPlayerJoin(event.getEntity().getUUID()); + } +} diff --git a/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/mixin/NeoForgeFloodgateUtilMixin.java b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/mixin/NeoForgeFloodgateUtilMixin.java new file mode 100644 index 0000000..cee3218 --- /dev/null +++ b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/mixin/NeoForgeFloodgateUtilMixin.java @@ -0,0 +1,27 @@ +package org.geysermc.floodgate.platform.neoforge.mixin; + +import org.geysermc.floodgate.core.util.Utils; +import org.geysermc.floodgate.mod.FloodgateMod; +import org.geysermc.floodgate.platform.neoforge.NeoForgeFloodgateMod; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +import java.lang.annotation.Annotation; +import java.util.Set; + +/** + * Mixin into Floodgate's {@link Utils} class as NeoForge is really picky about how it allows scanning + * mod-owned classes. + */ +@Mixin(value = Utils.class, remap = false) +public class NeoForgeFloodgateUtilMixin { + + /** + * @author geysermc + * @reason NeoForge is really picky about how it allows scanning mod-owned classes. + */ + @Overwrite(remap = false) + public static Set> getGeneratedClassesForAnnotation(Class annotationClass) { + return ((NeoForgeFloodgateMod) FloodgateMod.INSTANCE).getAnnotatedClasses(annotationClass); + } +} diff --git a/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/module/NeoForgeCommandModule.java b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/module/NeoForgeCommandModule.java new file mode 100644 index 0000000..5b06fe8 --- /dev/null +++ b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/module/NeoForgeCommandModule.java @@ -0,0 +1,29 @@ +package org.geysermc.floodgate.platform.neoforge.module; + +import com.google.inject.Provides; +import com.google.inject.Singleton; +import lombok.SneakyThrows; +import org.geysermc.floodgate.core.module.CommandModule; +import org.geysermc.floodgate.core.platform.command.CommandUtil; +import org.geysermc.floodgate.core.player.FloodgateCommandPreprocessor; +import org.geysermc.floodgate.core.player.UserAudience; +import org.geysermc.floodgate.core.player.audience.FloodgateSenderMapper; +import org.geysermc.floodgate.mod.util.ModCommandUtil; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.execution.ExecutionCoordinator; +import org.incendo.cloud.neoforge.NeoForgeServerCommandManager; + +public class NeoForgeCommandModule extends CommandModule { + @Provides + @Singleton + @SneakyThrows + public CommandManager commandManager(CommandUtil commandUtil) { + CommandManager commandManager = new NeoForgeServerCommandManager<>( + ExecutionCoordinator.simpleCoordinator(), + new FloodgateSenderMapper<>(commandUtil) + ); + commandManager.registerCommandPreProcessor(new FloodgateCommandPreprocessor<>(commandUtil)); + ((ModCommandUtil) commandUtil).setCommandManager(commandManager); + return commandManager; + } +} diff --git a/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/module/NeoForgePlatformModule.java b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/module/NeoForgePlatformModule.java new file mode 100644 index 0000000..f224ad0 --- /dev/null +++ b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/module/NeoForgePlatformModule.java @@ -0,0 +1,46 @@ +package org.geysermc.floodgate.platform.neoforge.module; + +import com.google.inject.Provides; +import com.google.inject.Scopes; +import com.google.inject.Singleton; +import com.google.inject.name.Named; +import org.geysermc.floodgate.core.platform.listener.ListenerRegistration; +import org.geysermc.floodgate.core.platform.pluginmessage.PluginMessageUtils; +import org.geysermc.floodgate.core.pluginmessage.PluginMessageRegistration; +import org.geysermc.floodgate.mod.listener.ModEventListener; +import org.geysermc.floodgate.mod.module.ModPlatformModule; +import org.geysermc.floodgate.platform.neoforge.listener.NeoForgeEventRegistration; +import org.geysermc.floodgate.platform.neoforge.pluginmessage.NeoForgePluginMessageRegistration; +import org.geysermc.floodgate.platform.neoforge.pluginmessage.NeoForgePluginMessageUtils; + +public class NeoForgePlatformModule extends ModPlatformModule { + + @Override + protected void configure() { + super.configure(); + + // We retrieve using NeoForgePluginMessageRegistration.class from our the mod class. + // We do this to ensure that injector#getInstance with either class returns the same singleton + bind(PluginMessageRegistration.class).to(NeoForgePluginMessageRegistration.class).in(Scopes.SINGLETON); + bind(NeoForgePluginMessageRegistration.class).toInstance(new NeoForgePluginMessageRegistration()); + } + + @Provides + @Singleton + public ListenerRegistration listenerRegistration() { + return new NeoForgeEventRegistration(); + } + + @Provides + @Singleton + public PluginMessageUtils pluginMessageUtils() { + return new NeoForgePluginMessageUtils(); + } + + @Provides + @Named("implementationName") + public String implementationName() { + return "NeoForge"; + } + +} diff --git a/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/pluginmessage/NeoForgePluginMessageRegistration.java b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/pluginmessage/NeoForgePluginMessageRegistration.java new file mode 100644 index 0000000..bd73bb3 --- /dev/null +++ b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/pluginmessage/NeoForgePluginMessageRegistration.java @@ -0,0 +1,39 @@ +package org.geysermc.floodgate.platform.neoforge.pluginmessage; + +import lombok.Setter; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; +import org.geysermc.floodgate.core.pluginmessage.PluginMessageChannel; +import org.geysermc.floodgate.core.pluginmessage.PluginMessageRegistration; +import org.geysermc.floodgate.mod.pluginmessage.payloads.FormPayload; +import org.geysermc.floodgate.mod.pluginmessage.payloads.PacketPayload; +import org.geysermc.floodgate.mod.pluginmessage.payloads.SkinPayload; +import org.geysermc.floodgate.mod.pluginmessage.payloads.TransferPayload; + +public class NeoForgePluginMessageRegistration implements PluginMessageRegistration { + + @Setter + private PayloadRegistrar registrar; + + @Override + public void register(PluginMessageChannel channel) { + switch (channel.getIdentifier()) { + case "floodgate:form" -> + registrar.playBidirectional(FormPayload.TYPE, FormPayload.STREAM_CODEC, (payload, context) -> + channel.handleServerCall(payload.data(), context.player().getUUID(), + context.player().getGameProfile().getName())); + case "floodgate:packet" -> + registrar.playBidirectional(PacketPayload.TYPE, PacketPayload.STREAM_CODEC, (payload, context) -> + channel.handleServerCall(payload.data(), context.player().getUUID(), + context.player().getGameProfile().getName())); + case "floodgate:skin" -> + registrar.playBidirectional(SkinPayload.TYPE, SkinPayload.STREAM_CODEC, (payload, context) -> + channel.handleServerCall(payload.data(), context.player().getUUID(), + context.player().getGameProfile().getName())); + case "floodgate:transfer" -> + registrar.playBidirectional(TransferPayload.TYPE, TransferPayload.STREAM_CODEC, (payload, context) -> + channel.handleServerCall(payload.data(), context.player().getUUID(), + context.player().getGameProfile().getName())); + default -> throw new IllegalArgumentException("unknown channel: " + channel); + } + } +} diff --git a/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/pluginmessage/NeoForgePluginMessageUtils.java b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/pluginmessage/NeoForgePluginMessageUtils.java new file mode 100644 index 0000000..5faf4d5 --- /dev/null +++ b/neoforge/src/main/java/org/geysermc/floodgate/platform/neoforge/pluginmessage/NeoForgePluginMessageUtils.java @@ -0,0 +1,37 @@ +package org.geysermc.floodgate.platform.neoforge.pluginmessage; + +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.server.level.ServerPlayer; +import net.neoforged.neoforge.network.PacketDistributor; +import org.geysermc.floodgate.core.platform.pluginmessage.PluginMessageUtils; +import org.geysermc.floodgate.mod.MinecraftServerHolder; +import org.geysermc.floodgate.mod.pluginmessage.payloads.FormPayload; +import org.geysermc.floodgate.mod.pluginmessage.payloads.PacketPayload; +import org.geysermc.floodgate.mod.pluginmessage.payloads.SkinPayload; +import org.geysermc.floodgate.mod.pluginmessage.payloads.TransferPayload; + +import java.util.Objects; +import java.util.UUID; + +public class NeoForgePluginMessageUtils extends PluginMessageUtils { + public boolean sendMessage(UUID uuid, String channel, byte[] data) { + try { + ServerPlayer player = MinecraftServerHolder.get().getPlayerList().getPlayer(uuid); + final CustomPacketPayload payload; + switch (channel) { + case "floodgate:form" -> payload = new FormPayload(data); + case "floodgate:packet" -> payload = new PacketPayload(data); + case "floodgate:skin" -> payload = new SkinPayload(data); + case "floodgate:transfer" -> payload = new TransferPayload(data); + default -> throw new IllegalArgumentException("unknown channel: " + channel); + } + + Objects.requireNonNull(player); + PacketDistributor.sendToPlayer(player, payload); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } +} diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..04901ca --- /dev/null +++ b/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,27 @@ +modLoader="javafml" +loaderVersion="[1,)" +license="MIT" +[[mods]] +modId="$id" +version="$version" +displayName="$name" +displayURL="$url" +logoFile= "../assets/floodgate/icon.png" +authors="$author" +description="$description" +[[mixins]] +config = "floodgate.mixins.json" +[[mixins]] +config = "floodgate_neoforge.mixins.json" +[[dependencies.floodgate]] +modId="neoforge" +type="required" +versionRange="[21.0.0-beta,)" +ordering="NONE" +side="BOTH" +[[dependencies.floodgate]] +modId="minecraft" +type="required" +versionRange="[$minecraft_version,)" +ordering="NONE" +side="BOTH" \ No newline at end of file diff --git a/neoforge/src/main/resources/floodgate_neoforge.mixins.json b/neoforge/src/main/resources/floodgate_neoforge.mixins.json new file mode 100644 index 0000000..9c06f8d --- /dev/null +++ b/neoforge/src/main/resources/floodgate_neoforge.mixins.json @@ -0,0 +1,12 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "org.geysermc.floodgate.platform.neoforge.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "NeoForgeFloodgateUtilMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 71ef923..5d93e26 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,8 +1,34 @@ +@file:Suppress("UnstableApiUsage") + +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") + pluginManagement { repositories { - //mavenLocal() - mavenCentral() gradlePluginPortal() + maven("https://repo.opencollab.dev/main/") + maven("https://jitpack.io") { + content { + includeGroupByRegex("com\\.github\\..*") + } + } + + maven("https://maven.architectury.dev/") + maven("https://maven.neoforged.net/releases") maven("https://maven.fabricmc.net/") } + + plugins { + id("net.kyori.blossom") + id("net.kyori.indra") + id("net.kyori.indra.git") + id("floodgate-modded.build-logic") + } + + includeBuild("build-logic") } + +rootProject.name = "floodgate-modded" + +include(":mod") +include(":fabric") +include(":neoforge") diff --git a/src/main/java/org/geysermc/floodgate/FabricMod.java b/src/main/java/org/geysermc/floodgate/FabricMod.java deleted file mode 100644 index e93365f..0000000 --- a/src/main/java/org/geysermc/floodgate/FabricMod.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.geysermc.floodgate; - -import net.fabricmc.api.EnvType; -import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; -import org.geysermc.floodgate.inject.fabric.FabricInjector; -import com.google.inject.Guice; -import com.google.inject.Injector; -import net.fabricmc.api.ModInitializer; -import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; -import net.fabricmc.loader.api.FabricLoader; -import org.geysermc.floodgate.api.logger.FloodgateLogger; -import org.geysermc.floodgate.module.*; -import org.geysermc.floodgate.util.FabricTemplateReader; - -public class FabricMod implements ModInitializer { - - private boolean started; - - @Override - public void onInitialize() { - FabricInjector.setInstance(new FabricInjector()); - - Injector injector = Guice.createInjector( - new ServerCommonModule(FabricLoader.getInstance().getConfigDir().resolve("floodgate"), new FabricTemplateReader()), - new FabricPlatformModule() - ); - - FloodgatePlatform platform = injector.getInstance(FloodgatePlatform.class); - - platform.enable(new FabricCommandModule()); - - ServerLifecycleEvents.SERVER_STARTED.register((server) -> { - long ctm = System.currentTimeMillis(); - - // Stupid hack, see the class for more information - // This can probably be Guice-i-fied but that is beyond me - MinecraftServerHolder.set(server); - - if (!started) { - platform.enable( - new FabricAddonModule(), - new FabricListenerModule(), - new PluginMessageModule() - ); - started = true; - } - - long endCtm = System.currentTimeMillis(); - injector.getInstance(FloodgateLogger.class) - .translatedInfo("floodgate.core.finish", endCtm - ctm); - }); - - if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { - ClientLifecycleEvents.CLIENT_STOPPING.register(($) -> { - platform.disable(); - }); - } else { - ServerLifecycleEvents.SERVER_STOPPING.register((server) -> { - platform.disable(); - }); - } - } -} diff --git a/src/main/java/org/geysermc/floodgate/listener/FabricEventRegistration.java b/src/main/java/org/geysermc/floodgate/listener/FabricEventRegistration.java deleted file mode 100644 index 43daf0f..0000000 --- a/src/main/java/org/geysermc/floodgate/listener/FabricEventRegistration.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.geysermc.floodgate.listener; - -import com.google.inject.Inject; -import lombok.RequiredArgsConstructor; -import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; -import org.geysermc.floodgate.platform.listener.ListenerRegistration; - -@RequiredArgsConstructor(onConstructor = @__(@Inject)) -public final class FabricEventRegistration implements ListenerRegistration { - @Override - public void register(FabricEventListener listener) { - ServerPlayConnectionEvents.JOIN.register(listener::onPlayerJoin); - } -} diff --git a/src/main/java/org/geysermc/floodgate/module/FabricListenerModule.java b/src/main/java/org/geysermc/floodgate/module/FabricListenerModule.java deleted file mode 100644 index ec67abc..0000000 --- a/src/main/java/org/geysermc/floodgate/module/FabricListenerModule.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.geysermc.floodgate.module; - -import com.google.inject.AbstractModule; -import com.google.inject.Singleton; -import com.google.inject.TypeLiteral; -import com.google.inject.multibindings.ProvidesIntoSet; -import org.geysermc.floodgate.listener.FabricEventListener; -import org.geysermc.floodgate.register.ListenerRegister; - -public final class FabricListenerModule extends AbstractModule { - @Override - protected void configure() { - bind(new TypeLiteral>() {}).asEagerSingleton(); - } - - @Singleton - @ProvidesIntoSet - public FabricEventListener fabricEventListener() { - return new FabricEventListener(); - } -} diff --git a/src/main/java/org/geysermc/floodgate/module/FabricPlatformModule.java b/src/main/java/org/geysermc/floodgate/module/FabricPlatformModule.java deleted file mode 100644 index 9a59283..0000000 --- a/src/main/java/org/geysermc/floodgate/module/FabricPlatformModule.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.geysermc.floodgate.module; - -import com.google.inject.name.Names; -import org.apache.logging.log4j.Logger; -import org.geysermc.floodgate.inject.fabric.FabricInjector; -import org.geysermc.floodgate.listener.FabricEventListener; -import org.geysermc.floodgate.listener.FabricEventRegistration; -import org.geysermc.floodgate.logger.Log4jFloodgateLogger; -import org.geysermc.floodgate.platform.listener.ListenerRegistration; -import org.geysermc.floodgate.platform.pluginmessage.PluginMessageUtils; -import org.geysermc.floodgate.platform.util.PlatformUtils; -import org.geysermc.floodgate.pluginmessage.FabricPluginMessageRegistration; -import org.geysermc.floodgate.pluginmessage.FabricPluginMessageUtils; -import org.geysermc.floodgate.pluginmessage.FabricSkinApplier; -import org.geysermc.floodgate.pluginmessage.PluginMessageRegistration; -import org.geysermc.floodgate.util.FabricCommandUtil; -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.Singleton; -import com.google.inject.name.Named; -import lombok.RequiredArgsConstructor; -import org.apache.logging.log4j.LogManager; -import org.geysermc.floodgate.api.FloodgateApi; -import org.geysermc.floodgate.api.logger.FloodgateLogger; -import org.geysermc.floodgate.inject.CommonPlatformInjector; -import org.geysermc.floodgate.platform.command.CommandUtil; -import org.geysermc.floodgate.skin.SkinApplier; -import org.geysermc.floodgate.util.FabricPlatformUtils; -import org.geysermc.floodgate.util.LanguageManager; - -@RequiredArgsConstructor -public final class FabricPlatformModule extends AbstractModule { - - @Override - protected void configure() { - bind(PlatformUtils.class).to(FabricPlatformUtils.class); - bind(Logger.class).annotatedWith(Names.named("logger")).toInstance(LogManager.getLogger("floodgate")); - bind(FloodgateLogger.class).to(Log4jFloodgateLogger.class); - } - - @Provides - @Singleton - public CommandUtil commandUtil( - FloodgateApi api, - FloodgateLogger logger, - LanguageManager languageManager) { - return new FabricCommandUtil(languageManager, api, logger); - } - - @Provides - @Singleton - public ListenerRegistration listenerRegistration() { - return new FabricEventRegistration(); - } - - /* - DebugAddon / PlatformInjector - */ - - @Provides - @Singleton - public CommonPlatformInjector platformInjector() { - return FabricInjector.getInstance(); - } - - @Provides - @Named("packetEncoder") - public String packetEncoder() { - return "encoder"; - } - - @Provides - @Named("packetDecoder") - public String packetDecoder() { - return "decoder"; - } - - @Provides - @Named("packetHandler") - public String packetHandler() { - return "packet_handler"; - } - - @Provides - @Singleton - public PluginMessageUtils pluginMessageUtils() { - return new FabricPluginMessageUtils(); - } - - @Provides - @Named("implementationName") - public String implementationName() { - return "Fabric"; - } - - @Provides - @Singleton - public PluginMessageRegistration pluginMessageRegister() { - return new FabricPluginMessageRegistration(); - } - - @Provides - @Singleton - public SkinApplier skinApplier() { - return new FabricSkinApplier(); - } -} diff --git a/src/main/java/org/geysermc/floodgate/util/FabricTemplateReader.java b/src/main/java/org/geysermc/floodgate/util/FabricTemplateReader.java deleted file mode 100644 index b772fde..0000000 --- a/src/main/java/org/geysermc/floodgate/util/FabricTemplateReader.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.geysermc.floodgate.util; - -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.ModContainer; -import org.geysermc.configutils.file.template.TemplateReader; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.util.Optional; - -public class FabricTemplateReader implements TemplateReader { - - private final ModContainer container; - - public FabricTemplateReader() { - container = FabricLoader.getInstance().getModContainer("floodgate").orElseThrow(); - } - - @Override - public BufferedReader read(String configName) { - Optional optional = container.findPath(configName); - if (optional.isPresent()) { - try { - InputStream stream = optional.get().getFileSystem() - .provider() - .newInputStream(optional.get()); - return new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8)); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - return null; - } -} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json deleted file mode 100644 index 24b3009..0000000 --- a/src/main/resources/fabric.mod.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "schemaVersion": 1, - "id": "floodgate", - "version": "${version}", - "name": "Floodgate-Fabric", - "description": "", - "authors": [ - "GeyserMC" - ], - "contact": { - "website": "https://geysermc.org", - "repo": "https://github.com/GeyserMC/Floodgate-Fabric" - }, - "license": "MIT", - "icon": "assets/floodgate/icon.png", - "environment": "*", - "entrypoints": { - "main": [ - "org.geysermc.floodgate.FabricMod" - ] - }, - "accessWidener": "floodgate.accesswidener", - "mixins": [ - "floodgate.mixins.json" - ], - "depends": { - "fabricloader": ">=0.15.11", - "fabric": "*", - "minecraft": ">=1.21" - } -} \ No newline at end of file