Jump to content

Forge 1.21.6/1.21.7/1.21.8: Missing or Broken @SubscribeEvent Annotation in EventBus API


Recommended Posts

Posted

Hello,

I'm encountering a compilation issue with Forge 1.21.6.
The exact same mod code works perfectly on Forge 1.19.2 up to 1.21.5, but starting with 1.21.6, it fails to compile due to missing Forge classes.

Here’s a snippet of the errors:

kotlin

CopierModifier

BetterGamemode.java:9: error: package net.minecraftforge.eventbus.api does not exist import net.minecraftforge.eventbus.api.SubscribeEvent; ^ BetterGamemode.java:29: error: cannot find symbol @SubscribeEvent ^ symbol: class SubscribeEvent

I already tried:

Clearing .gradle and .minecraft caches

Running --refresh-dependencies

Validating my build.gradle setup (it works fine in 1.21.5)

build.gradle

plugins {
    id 'eclipse'
    id 'idea'
    id 'maven-publish'
    id 'net.minecraftforge.gradle' version '[6.0.36,6.2)'
}

version = mod_version
group = mod_group_id

base {
    archivesName = mod_id
}

// Mojang ships Java 21 to end users in 1.20.5+, so your mod should target Java 21.
java.toolchain.languageVersion = JavaLanguageVersion.of(21)

println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}"
minecraft {
    // The mappings can be changed at any time and must be in the following format.
    // Channel:   Version:
    // official   MCVersion             Official field/method names from Mojang mapping files
    // parchment  YYYY.MM.DD-MCVersion  Open community-sourced parameter names and javadocs layered on top of official
    //
    // Parchment is an unofficial project maintained by ParchmentMC, separate from MinecraftForge
    // Additional setup is needed to use their mappings: https://parchmentmc.org/docs/getting-started
    //
    // Simply re-run your setup task after changing the mappings to update your workspace.
    mappings channel: mapping_channel, version: mapping_version

    // Forge 1.20.6 and newer use official mappings at runtime, so we shouldn't reobf from official to SRG
    reobf = false

    // When true, this property will have all Eclipse/IntelliJ IDEA run configurations run the "prepareX" task for the given run configuration before launching the game.
    // In most cases, it is not necessary to enable.
    // enableEclipsePrepareRuns = true
    // enableIdeaPrepareRuns = true

    // This property allows configuring Gradle's ProcessResources task(s) to run on IDE output locations before launching the game.
    // It is REQUIRED to be set to true for this template to function.
    // See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html
    copyIdeResources = true

    // When true, this property will add the folder name of all declared run configurations to generated IDE run configurations.
    // The folder name can be set on a run configuration using the "folderName" property.
    // By default, the folder name of a run configuration is the name of the Gradle project containing it.
    // generateRunFolders = true

    // This property enables access transformers for use in development, applied to the Minecraft artifact.
    // The access transformer file can be anywhere in the project.
    // However, it must be at "META-INF/accesstransformer.cfg" in the final mod jar to be loaded by Forge.
    // This default location is a best practice to automatically put the file in the right place in the final jar.
    // See https://docs.minecraftforge.net/en/latest/advanced/accesstransformers/ for more information.
    // accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')se can be tweaked, removed, or duplicated as needed.
    //    runs {
    //        // applies to all the run configs below
    //        configureEach {
    //            workingDirectory project.file('run')
    //
    //            // Optional additional logging. The markers can be added/remove as needed, separated by commas.
    //            // "SCAN": For mods scan.
    //            // "REGISTRIES": For firing of registry events.
    //            // "REGISTRYDUMP": For getting the contents of all registries.
    ////            property 'forge.logging.markers', 'REGISTRIES'
    //
    //            property 'forge.logging.console.level', 'debug'
    //
    ////            arg "-mixin.config=${mod_id}.mixins.json"
    //        }
    //
    //        client {
    //            // Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
    //            property 'forge.enabledGameTestNamespaces', mod_id
    //        }
    //
    //        server {
    //            property 'forge.enabledGameTestNamespaces', mod_id
    //            args '--nogui'
    //        }
    //
    //        // This run config launches GameTestServer and runs all registered gametests, then exits.
    //        // By default, the server will crash when no gametests are provided.
    //        // The gametest system is also enabled by default for other run configs under the /test command.
    //        gameTestServer {
    //            property 'forge.enabledGameTestNamespaces', mod_id
    //        }
    //
    //        data {
    //            // example of overriding the workingDirectory set in configureEach above
    //            workingDirectory project.file('run-data')
    //
    //            // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
    //            args '--mod', mod_id, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
    //        }
    //    }
    //}
    //
    //// Include resources generated by data generators.
    //sourceSets.main.resources { srcDir 'src/generated/resources' }
    //
    //repositories {
    //    // Put repositories for dependencies here
    //    mavenCentral()
    //    maven {
    //        name = 'Forge'
    //        url = 'https://maven.minecraftforge.net'
    //    }
    //    maven {
    //        name = 'Minecraft libraries'
    //        url = 'https://libraries.minecraft.net'
    //    }
    //    exclusiveContent {
    //        forRepository {
    //            maven {
    //                name = 'Sponge'
    //                url = 'https://repo.spongepowered.org/repository/maven-public'
    //            }
    //        }
    //        filter {
    //            includeGroupAndSubgroups('org.spongepowered')
    //        }
    //    }
    //
    //    // If you have mod jar dependencies in ./libs, you can declare them as a repository like so.
    //    // See https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver
    //    // flatDir {
    //    //     dir 'libs'
    //    // }
    //}
    //
    //dependencies {
    //    // Specify the version of Minecraft to use.
    //    // Any artifact can be supplied so long as it has a "userdev" classifier artifact and is a compatible patcher artifact.
    //    // The "userdev" classifier will be requested and setup by ForgeGradle.
    //    // If the group id is "net.minecraft" and the artifact id is one of ["client", "server", "joined"],
    //    // then special handling is done to allow a setup of a vanilla dependency without the use of an external repository.
    //    minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
    //
    //    // Example mod dependency with JEI
    //    // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime
    //    // compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}"
    //    // compileOnly "mezz.jei:jei-${mc_version}-forge-api:${jei_version}"
    //    // runtimeOnly "mezz.jei:jei-${mc_version}-forge:${jei_version}"
    //    implementation "net.minecraftforge:eventbus:<version>"
    //    // Example mod dependency using a mod jar from ./libs with a flat dir repository
    //    // This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar
    //    // The group id is ignored when searching -- in this case, it is "blank"
    //    // implementation fg.deobf("blank:coolmod-${mc_version}:${coolmod_version}")
    //
    //    // For more info:
    //    // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
    //    // http://www.gradle.org/docs/current/userguide/dependency_management.html
    //}
    //
    //// This block of code expands all declared replace properties in the specified resource targets.
    //// A missing property will result in an error. Properties are expanded using ${} Groovy notation.
    //// When "copyIdeResources" is enabled, this will also run before the game launches in IDE environments.
    //// See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html
    //tasks.named('processResources', ProcessResources) {
    //    var replaceProperties = [
    //            minecraft_version: minecraft_version, minecraft_version_range: minecraft_version_range,
    //            forge_version: forge_version, forge_version_range: forge_version_range,
    //            loader_version_range: loader_version_range,
    //            mod_id: mod_id, mod_name: mod_name, mod_license: mod_license, mod_version: mod_version,
    //            mod_authors: mod_authors, mod_description: mod_description,
    //    ]
    //    inputs.properties replaceProperties
    //
    //    filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) {
    //        expand replaceProperties + [project: project]
    //    }
    //}
    //
    //// Example for how to get properties into the manifest for reading at runtime.
    //tasks.named('jar', Jar) {
    //    manifest {
    //        attributes([
    //            'Specification-Title'     : mod_id,
    //            'Specification-Vendor'    : mod_authors,
    //            'Specification-Version'   : '1', // We are version 1 of ourselves
    //            'Implementation-Title'    : project.name,
    //            'Implementation-Version'  : project.jar.archiveVersion,
    //            'Implementation-Vendor'   : mod_authors
    //        ])
    ////        attributes['MixinConfigs'] = "${mod_id}.mixins.json"
    //    }
    //}
    //
    //// Example configuration to allow publishing using the maven-publish plugin
    //publishing {
    //    publications {
    //        register('mavenJava', MavenPublication) {
    //            artifact jar
    //        }
    //    }
    //    repositories {
    //        maven {
    //            url "file://${project.projectDir}/mcmodsrepo"
    //        }
    //    }
    //}
    //
    //tasks.withType(JavaCompile).configureEach {
    //    options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
    //}
    //
    //// IntelliJ no longer downloads javadocs and sources by default, this tells Gradle to force IntelliJ to do it.
    //idea.module { downloadJavadoc = downloadSources = true }
    //
    //eclipse {
    //    // Run everytime eclipse builds the code
    //    //autoBuildTasks genEclipseRuns
    //    // Run when importing the project
    //    synchronizationTasks 'genEclipseRuns'
    //}
    //
    //// Merge the resources and classes into the same directory, because Java expects modules to be in a single directory.
    //// And if we have it in multiple we have to do performance intensive hacks like having the UnionFileSystem
    //// This will eventually be migrated to ForgeGradle so modders don't need to manually do it. But that is later.
    //sourceSets.each {
    //    def dir = layout.buildDirectory.dir("sourcesSets/$it.name")
    //    it.output.resourcesDir = dir
    //    it.java.destinationDirectory = dir
    //}

    // Default run configurations.
    // The


BetterGamemode.java

package net.onehype.bettergamemode;

import net.minecraft.client.KeyMapping;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.InputEvent;
import net.minecraftforge.client.event.RegisterKeyMappingsEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegisterCommandsEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.lwjgl.glfw.GLFW;

@Mod(BetterGamemode.MODID)
public class BetterGamemode {
    public static final String MODID = "bettergamemode";

    public static KeyMapping keyCreative;
    public static KeyMapping keySurvival;
    public static KeyMapping keySpectator;
    public static KeyMapping keyAdventure;

    public BetterGamemode() {
        MinecraftForge.EVENT_BUS.register(this);
        // On supprime la ligne qui cause l'erreur car on ne l'utilise pas
        // FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientSetup);
    }

    @SubscribeEvent
    public void onRegisterCommands(RegisterCommandsEvent event) {
        GamemodeCommand.register(event.getDispatcher());
    }

    @Mod.EventBusSubscriber(modid = BetterGamemode.MODID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD)
    public static class KeybindHandler {

        @SubscribeEvent
        public static void registerKeyMappings(RegisterKeyMappingsEvent event) {
            keyCreative = new KeyMapping("creative", GLFW.GLFW_KEY_M, "better gamemode");
            keySurvival = new KeyMapping("survival", GLFW.GLFW_KEY_N, "better gamemode");
            keySpectator = new KeyMapping("spectator", GLFW.GLFW_KEY_P, "better gamemode");
            keyAdventure = new KeyMapping("adventure", GLFW.GLFW_KEY_K, "better gamemode");

            event.register(keyCreative);
            event.register(keySurvival);
            event.register(keySpectator);
            event.register(keyAdventure);
        }
    }

    @SubscribeEvent
    public void onKeyInput(InputEvent.Key event) {
        // On vérifie les touches enfoncées avec isDown() et on change le gamemode
        if (keyCreative != null && keyCreative.isDown()) {
            GamemodeUtils.changeGamemode(1);
        }
        if (keySurvival != null && keySurvival.isDown()) {
            GamemodeUtils.changeGamemode(0);
        }
        if (keySpectator != null && keySpectator.isDown()) {
            GamemodeUtils.changeGamemode(3);
        }
        if (keyAdventure != null && keyAdventure.isDown()) {
            GamemodeUtils.changeGamemode(2);
        }
    }
}

GamemodeCommand.java
 

package net.onehype.bettergamemode;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.GameType;

public class GamemodeCommand {
    public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
        dispatcher.register(Commands.literal("gm")
                .then(Commands.argument("mode", StringArgumentType.word())
                        .executes(context -> {
                            String mode = StringArgumentType.getString(context, "mode");
                            CommandSourceStack source = context.getSource();

                            if (source.getEntity() instanceof ServerPlayer player) {
                                switch (mode.toLowerCase()) {
                                    case "s":
                                        player.setGameMode(GameType.SURVIVAL);
                                        player.displayClientMessage(Component.literal("You are now in Survival mode."), false);
                                        break;
                                    case "c":
                                        player.setGameMode(GameType.CREATIVE);
                                        player.displayClientMessage(Component.literal("You are now in Creative mode."), false);
                                        break;
                                    case "a":
                                        player.setGameMode(GameType.ADVENTURE);
                                        player.displayClientMessage(Component.literal("You are now in Adventure mode."), false);
                                        break;
                                    case "sp":
                                        player.setGameMode(GameType.SPECTATOR);
                                        player.displayClientMessage(Component.literal("You are now in Spectator mode."), false);
                                        break;
                                    default:
                                        player.displayClientMessage(Component.literal("Invalid mode. Use /gm <s|c|a|sp>."), false);
                                }
                            }
                            return 1;
                        })));
    }
}

GamemodeUtils.java

 

package net.onehype.bettergamemode;

import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.GameType;
import net.minecraftforge.server.ServerLifecycleHooks;

public class GamemodeUtils {
    public static void changeGamemode(ServerPlayer player, int mode) {
        GameType gameType = GameType.byId(mode);
        player.setGameMode(gameType);
        player.displayClientMessage(Component.literal("Gamemode changed to " + gameType.getName() + "."), false);
    }

    public static void changeGamemode(int mode) {
        MinecraftServer server = getServerInstance();
        if (server != null) {
            if (server.isSingleplayer()) {
                ServerPlayer player = server.getPlayerList().getPlayers().stream().findFirst().orElse(null);
                if (player != null) {
                    changeGamemode(player, mode);
                }
            }
        }
    }

    private static MinecraftServer getServerInstance() {
        return ServerLifecycleHooks.getCurrentServer();
    }
}

 

Posted

Hi, I just encountered this same error. It appears the SubscribeEvent class has been moved from:

net.minecraftforge.eventbus.api.SubscribeEvent

to:

net.minecraftforge.eventbus.api.listener.SubscribeEvent

 

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.