Jump to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

theodene

Members
  • Joined

  • Last visited

  1. theodene joined the community
  2. 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(); } }

Important Information

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

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.