I am trying to build a plugin for a Minecraft Spigot server that ultimately I would like to be able to communicate over serial with things connected to my PC (server is running locally on the PC as well).
I have been able to build and run the plugin and manipulate player/blocks in the game so I know the build process for my base plugin is working. My trouble started when I began trying to include an extra dependency: jSerialComm
I added the dependency entry in my pom.xml file:
<dependency>
<groupId>com.fazecast</groupId>
<artifactId>jSerialComm</artifactId>
<version>[2.0.0,3.0.0)</version>
<scope>provided</scope>
</dependency>
I added some basic code to import classes from jSerialComm
and do something basic with them inside of a command in my plugin:
import com.fazecast.jSerialComm.SerialPort;
public class CommandCheck implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (sender instanceof Player){
System.out.println(SerialPort.getCommPorts());
}
return false;
}
}
This builds fine, I'm using InteliJ and it does recognize the SerialPort class (no red underlines).
But when this command runs in the game I get a Class Not Found error:
org.bukkit.command.CommandException: Unhandled exception executing command 'check' in plugin MyFirstPlugin v1.0-SNAPSHOT
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:47) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:149) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
at org.bukkit.craftbukkit.v1_18_R1.CraftServer.dispatchCommand(CraftServer.java:821) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.server.network.PlayerConnection.a(PlayerConnection.java:1939) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.server.network.PlayerConnection.a(PlayerConnection.java:1778) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.server.network.PlayerConnection.a(PlayerConnection.java:1759) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.network.protocol.game.PacketPlayInChat.a(PacketPlayInChat.java:46) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.network.protocol.game.PacketPlayInChat.a(PacketPlayInChat.java:1) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.network.protocol.PlayerConnectionUtils.lambda$0(PlayerConnectionUtils.java:30) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.server.TickTask.run(SourceFile:18) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.util.thread.IAsyncTaskHandler.c(SourceFile:151) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.util.thread.IAsyncTaskHandlerReentrant.c(SourceFile:23) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.server.MinecraftServer.b(MinecraftServer.java:1158) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.server.MinecraftServer.c(MinecraftServer.java:1) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.util.thread.IAsyncTaskHandler.y(SourceFile:125) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.server.MinecraftServer.bf(MinecraftServer.java:1137) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.server.MinecraftServer.y(MinecraftServer.java:1130) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.util.thread.IAsyncTaskHandler.c(SourceFile:134) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.server.MinecraftServer.x(MinecraftServer.java:1114) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:1038) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at net.minecraft.server.MinecraftServer.lambda$0(MinecraftServer.java:304) ~[spigot-1.18.1-R0.1-SNAPSHOT.jar:3380-Spigot-8965a50-0ba6b90]
at java.lang.Thread.run(Thread.java:833) [?:?]
Caused by: java.lang.NoClassDefFoundError: com/fazecast/jSerialComm/SerialPort
at com.foamyguy.myfirstplugin.CommandCheck.onCommand(CommandCheck.java:21) ~[?:?]
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:45) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
... 21 more
Caused by: java.lang.ClassNotFoundException: com.fazecast.jSerialComm.SerialPort
at org.bukkit.plugin.java.PluginClassLoader.loadClass0(PluginClassLoader.java:147) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.java.PluginClassLoader.loadClass(PluginClassLoader.java:99) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:520) ~[?:?]
at com.foamyguy.myfirstplugin.CommandCheck.onCommand(CommandCheck.java:21) ~[?:?]
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:45) ~[spigot-api-1.18.1-R0.1-SNAPSHOT.jar:?]
... 21 more
I have unzipped and looked inside of the built jar file and the jSerialComm jar file is successfully being included within my plugin jar:
What do I need to do in order to successfully use an external JAR file (jSerialComm specifically) from inside of a Minecraft plugin? Or alternatively, is there some built-in way that I can connect and communicate over serial ports without needing an external JAR and therefore not needing anything "special" in order to work?
CodePudding user response:
Even if the JAR is present in your plugin, the classes of the JAR are not loaded in the classpath and Spigot cannot access the classes.
You can use a plugin, such as the maven-shade-plugin, which copies all classes from your API-JAR to your Plugin-JAR.
First, set the scope from provided
to compile
.
<dependency>
<groupId>com.fazecast</groupId>
<artifactId>jSerialComm</artifactId>
<version>[2.0.0,3.0.0)</version>
<scope>compile</scope> <!-- -->
</dependency>
Then add the maven-shade-plugin
under build > plugins
inside your pom.xml
<build>
<!-- ... -->
<plugins>
<!-- ... -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- ... -->
</plugins>
<!-- ... -->
</build>
If you now build the jar (using e. g. man clean package
), there should be a "fat-" jar file in the target/ folder that contains the classes of the API as well as your classes.
Contents of your plugin before:
├ com
├ foamguy
└ myfirstplugin
└ ...
├ plugin.yml
└ jSerialComm-xxx.jar
Contents of your plugin after:
├ com
├ foamguy
└ myfirstplugin
└ ...
└ fazecast
└ jSerialComm
└ ...
└ plugin.yml