I am creating a simple mod for minecraft version 1.19.2. I downloaded forge 1.19.2-43.0 and decided to add a dependency of a third-party java library. or rather, the twitch4j library (https://github.com/twitch4j )
the main idea of my mod is to output messages from the live chat of my twitch channel to the minecraft chat.
I have one class in the project:
package net.alerto.minetwitch;
import com.github.philippheuer.credentialmanager.domain.OAuth2Credential;
import com.github.twitch4j.TwitchClient;
import com.github.twitch4j.TwitchClientBuilder;
import com.github.twitch4j.chat.events.channel.ChannelMessageEvent;
import com.mojang.logging.LogUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.slf4j.Logger;
@Mod(MineTwitch.MOD_ID)
public class MineTwitch {
public static final String MOD_ID = "minetwitch";
private static final Logger LOGGER = LogUtils.getLogger();
public MineTwitch() {
TwitchClient twitchClient = TwitchClientBuilder.builder()
.withChatAccount(new OAuth2Credential("twitch", "YOUR_TWITCH_OAUTH_TOKEN"))
.withEnableChat(true)
.build();
twitchClient.getEventManager().onEvent(ChannelMessageEvent.class, this::handleChannelMessage);
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
modEventBus.addListener(this::commonSetup);
MinecraftForge.EVENT_BUS.register(this);
}
private void commonSetup(final FMLCommonSetupEvent event) {}
private void handleChannelMessage(ChannelMessageEvent event) {
String username = event.getUser().getName();
String message = event.getMessage();
Minecraft.getInstance().player.displayClientMessage(Component.literal("[" + username + "]: " + message), true);
}
}
and here's the build.gradle:
plugins {
id 'eclipse'
id 'idea'
id 'maven-publish'
id 'net.minecraftforge.gradle' version '[6.0,6.2)'
id 'com.github.johnrengelman.shadow' version '8.1.1'
}
version = '0.1-1.19.2'
group = 'net.alerto.minetwitch'
base {
archivesName = 'minetwitch'
}
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
println "Java: ${System.getProperty 'java.version'}, JVM: ${System.getProperty 'java.vm.version'} (${System.getProperty 'java.vendor'}), Arch: ${System.getProperty 'os.arch'}"
minecraft {
mappings channel: mapping_channel, version: mapping_version
copyIdeResources = true
runs {
configureEach {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
property 'forge.enabledGameTestNamespaces', 'minetwitch'
mods {
"${'minetwitch'}" {
source sourceSets.main
}
}
}
client {
property 'forge.enabledGameTestNamespaces', 'minetwitch'
}
server {
property 'forge.enabledGameTestNamespaces', 'minetwitch'
args '--nogui'
}
gameTestServer {
property 'forge.enabledGameTestNamespaces', 'minetwitch'
}
data {
workingDirectory project.file('run-data')
args '--mod', 'minetwitch', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
}
}
}
sourceSets.main.resources { srcDir 'src/generated/resources' }
repositories {
mavenCentral()
}
dependencies {
minecraft 'net.minecraftforge:forge:1.19.2-43.3.0'
implementation 'com.github.twitch4j:twitch4j:1.19.0'
implementation 'com.github.philippheuer.events4j:events4j-api:0.12.1'
implementation 'com.github.philippheuer.events4j:events4j-core:0.12.1'
}
tasks.named('processResources', ProcessResources).configure {
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,
'minetwitch': 'minetwitch', 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]
}
}
tasks.named('jar', Jar).configure {
manifest {
attributes([
'Specification-Title' : 'minetwitch',
'Specification-Vendor' : mod_authors,
'Specification-Version' : '1',
'Implementation-Title' : project.name,
'Implementation-Version' : project.jar.archiveVersion,
'Implementation-Vendor' : mod_authors,
'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
])
}
}
publishing {
publications {
register('mavenJava', MavenPublication) {
artifact jar
}
}
repositories {
mavenCentral()
maven {
url "file://${project.projectDir}/mcmodsrepo"
}
maven { url = 'https://jitpack.io' }
}
}
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
}
tasks.jar {
doFirst {
zip64 true
}
}
jar {
from {
duplicatesStrategy DuplicatesStrategy.INCLUDE
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
}
I'm using:
intellij idea 2021.3
java 17
twitch4j 1.19.0
forge 1.19.2-43.0
everything works in intellij, all dependencies are lifted and I can write the code calmly, there are no errors, I also build in gradle without errors. but when I run the run Client or copy the compiled jar to the mods folder, minecraft starts with the mod error, here are the logs:
---- Minecraft Crash Report ----
// Surprise! Haha. Well, this is awkward.
Time: 2024-01-27 21:32:20
Description: Mod loading error has occurred
java.lang.Exception: Mod Loading has failed
at net.minecraftforge.logging.CrashReportExtender.dumpModLoadingCrashReport(CrashReportExtender.java:55) ~[forge-1.19.2-43.3.0_mapped_official_1.19.2-recomp.jar%23187%23194!/:?] {re:classloading}
at net.minecraftforge.client.loading.ClientModLoader.completeModLoading(ClientModLoader.java:167) ~[forge-1.19.2-43.3.0_mapped_official_1.19.2-recomp.jar%23187%23194!/:?] {re:classloading,pl:runtimedistcleaner:A}
at net.minecraft.client.Minecraft.lambda$new$2(Minecraft.java:585) ~[forge-1.19.2-43.3.0_mapped_official_1.19.2-recomp.jar%23188!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
at net.minecraft.Util.ifElse(Util.java:438) ~[forge-1.19.2-43.3.0_mapped_official_1.19.2-recomp.jar%23188!/:?] {re:classloading}
at net.minecraft.client.Minecraft.lambda$new$3(Minecraft.java:579) ~[forge-1.19.2-43.3.0_mapped_official_1.19.2-recomp.jar%23188!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
at net.minecraft.client.gui.screens.LoadingOverlay.render(LoadingOverlay.java:135) ~[forge-1.19.2-43.3.0_mapped_official_1.19.2-recomp.jar%23188!/:?] {re:classloading,pl:runtimedistcleaner:A}
at net.minecraft.client.renderer.GameRenderer.render(GameRenderer.java:885) ~[forge-1.19.2-43.3.0_mapped_official_1.19.2-recomp.jar%23188!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
at net.minecraft.client.Minecraft.runTick(Minecraft.java:1115) ~[forge-1.19.2-43.3.0_mapped_official_1.19.2-recomp.jar%23188!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
at net.minecraft.client.Minecraft.run(Minecraft.java:700) ~[forge-1.19.2-43.3.0_mapped_official_1.19.2-recomp.jar%23188!/:?] {re:classloading,pl:accesstransformer:B,pl:runtimedistcleaner:A}
at net.minecraft.client.main.Main.run(Main.java:212) ~[forge-1.19.2-43.3.0_mapped_official_1.19.2-recomp.jar%23188!/:?] {re:classloading,pl:runtimedistcleaner:A}
at net.minecraft.client.main.Main.main(Main.java:51) ~[forge-1.19.2-43.3.0_mapped_official_1.19.2-recomp.jar%23188!/:?] {re:classloading,pl:runtimedistcleaner:A}
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] {}
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?] {}
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] {}
at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?] {}
at net.minecraftforge.fml.loading.targets.ForgeClientUserdevLaunchHandler.lambda$launchService$0(ForgeClientUserdevLaunchHandler.java:25) ~[fmlloader-1.19.2-43.3.0.jar%23101!/:?] {}
at cpw.mods.modlauncher.LaunchServiceHandlerDecorator.launch(LaunchServiceHandlerDecorator.java:30) [modlauncher-10.0.9.jar%23114!/:?] {}
at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:53) [modlauncher-10.0.9.jar%23114!/:?] {}
at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:71) [modlauncher-10.0.9.jar%23114!/:?] {}
at cpw.mods.modlauncher.Launcher.run(Launcher.java:108) [modlauncher-10.0.9.jar%23114!/:?] {}
at cpw.mods.modlauncher.Launcher.main(Launcher.java:78) [modlauncher-10.0.9.jar%23114!/:?] {}
at cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:26) [modlauncher-10.0.9.jar%23114!/:?] {}
at cpw.mods.modlauncher.BootstrapLaunchConsumer.accept(BootstrapLaunchConsumer.java:23) [modlauncher-10.0.9.jar%23114!/:?] {}
at cpw.mods.bootstraplauncher.BootstrapLauncher.main(BootstrapLauncher.java:141) [bootstraplauncher-1.1.2.jar:?] {}
A detailed walkthrough of the error, its code path and all known details is as follows:
---------------------------------------------------------------------------------------
-- Head --
Thread: Render thread
Stacktrace:
at jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) ~[?:?] {}
-- MOD minetwitch --
Details:
Caused by 0: java.lang.reflect.InvocationTargetException
at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?] {}
at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) ~[?:?] {}
at jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:?] {}
at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[?:?] {}
at java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[?:?] {}
at net.minecraftforge.fml.javafmlmod.FMLModContainer.constructMod(FMLModContainer.java:68) ~[javafmllanguage-1.19.2-43.3.0.jar%23189!/:?] {}
at net.minecraftforge.fml.ModContainer.lambda$buildTransitionHandler$10(ModContainer.java:121) ~[fmlcore-1.19.2-43.3.0.jar%23192!/:?] {}
at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1804) ~[?:?] {}
at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1796) ~[?:?] {}
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373) ~[?:?] {}
at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182) ~[?:?] {}
at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655) ~[?:?] {}
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622) ~[?:?] {}
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165) ~[?:?] {}
Caused by 1: java.lang.NoClassDefFoundError: com/github/twitch4j/TwitchClientBuilder
at net.alerto.minetwitch.MineTwitch.<init>(MineTwitch.java:28) ~[%23193!/:?] {re:classloading}
at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?] {}
at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) ~[?:?] {}
at jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:?] {}
at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[?:?] {}
at java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[?:?] {}
at net.minecraftforge.fml.javafmlmod.FMLModContainer.constructMod(FMLModContainer.java:68) ~[javafmllanguage-1.19.2-43.3.0.jar%23189!/:?] {}
at net.minecraftforge.fml.ModContainer.lambda$buildTransitionHandler$10(ModContainer.java:121) ~[fmlcore-1.19.2-43.3.0.jar%23192!/:?] {}
at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1804) ~[?:?] {}
at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1796) ~[?:?] {}
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373) ~[?:?] {}
at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182) ~[?:?] {}
at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655) ~[?:?] {}
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622) ~[?:?] {}
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165) ~[?:?] {}
Mod File: /E:/Java projects/Orther/Mine_Twitch/build/resources/main/
Failure message: Example Mod (minetwitch) has failed to load correctly
java.lang.reflect.InvocationTargetException: null
Mod Version: 0.1-1.19.2
Mod Issue URL: NOT PROVIDED
Exception message: java.lang.ClassNotFoundException: com.github.twitch4j.TwitchClientBuilder
Stacktrace:
at jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) ~[?:?] {}
at java.lang.ClassLoader.loadClass(ClassLoader.java:520) ~[?:?] {}
at cpw.mods.cl.ModuleClassLoader.loadClass(ModuleClassLoader.java:137) ~[securejarhandler-2.1.4.jar:?] {}
at java.lang.ClassLoader.loadClass(ClassLoader.java:520) ~[?:?] {}
at cpw.mods.cl.ModuleClassLoader.loadClass(ModuleClassLoader.java:137) ~[securejarhandler-2.1.4.jar:?] {}
at java.lang.ClassLoader.loadClass(ClassLoader.java:520) ~[?:?] {}
at net.alerto.minetwitch.MineTwitch.<init>(MineTwitch.java:28) ~[%23193!/:?] {re:classloading}
at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?] {}
at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) ~[?:?] {}
at jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[?:?] {}
at java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[?:?] {}
at java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[?:?] {}
at net.minecraftforge.fml.javafmlmod.FMLModContainer.constructMod(FMLModContainer.java:68) ~[javafmllanguage-1.19.2-43.3.0.jar%23189!/:?] {}
at net.minecraftforge.fml.ModContainer.lambda$buildTransitionHandler$10(ModContainer.java:121) ~[fmlcore-1.19.2-43.3.0.jar%23192!/:?] {}
at java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1804) ~[?:?] {}
at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:1796) ~[?:?] {}
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373) ~[?:?] {}
at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182) ~[?:?] {}
at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655) ~[?:?] {}
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622) ~[?:?] {}
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165) ~[?:?] {}
What could be the problem? It is the TwitchClientBuilder class that does not find it. Which I have already done. I have added a plugin for building with johnrengelman shadow libraries. what can be done if the jar is created correctly and with all libraries, but minecraft itself does not see it.
In the following the solution, that worked for me. Keep in mind, I developed in fabric so it might not work in forge. Because of fabric api, I can't use the shadow library (essentially the api is included twice), but maybe in your case, this is enough and the error is somewhere else. I assume that minecraft is included twice for forge with shadow, though.
In the
build.gradle-file, in add to theconfigurations-block:Which gives the following
configurationsblock if not already present:For every dependency you need (in your case: com.github.twitch4j:twitch4j:1.19.0), add
to the dependency block (that always exists in a minecraft mod), so in your case:
To the jar-Block add the following and create the jar block if not already present:
giving the following jar:
For further information on that question, type in "gradle fat jar" in google.
edit:
you can change every occurance of
includedJarswith any name you want (excluding keywords of course)edit2:
if it is difficult to follow, what I said, maybe you find this article from baeldung better: https://www.baeldung.com/gradle-fat-jar