[Tutorial] Adding custom sounds to your plugin (well… sort of)

Discussion in 'Resources' started by Quantum64, Mar 26, 2014.

Thread Status:
Not open for further replies.
  1. Offline

    Quantum64

    Adding custom sounds to your plugin (well… sort of)
    A Bukkit development resource by Quantum64

    On The hive MC, a new Minigame was recently introduced called “Block Party”. This game involved the player clicking a link to a web page and hearing sounds from the plugin through their web browser. In this tutorial we will create a similar system for playing custom sounds and/or music.

    Now before we get into this tutorial, I want to offer a bit of an advisory. This tutorial requires you to have a decent amount of Java knowledge. It is not a complicated project, but the techniques used are much more complicated than Listeners and calling methods in the Bukkit API. For instance, I expect you to have a decent understanding of Maven before we start., as well as semi advanced Java concepts and design pattern knowledge.

    To begin with, we are going to set up Maven. I figure this is going to be the most boring and probably time consuming part of the tutorial, so we minds well get it out of the way first. If you know how to create a POM file and integrate Maven into your IDE, great! If not, now is a good time to learn. Google search “Integrate maven with [MyAwesomeIDEHere]”, and get started with a basic tutorial. Done that? Good. We’re going to set up the POM file now. So go ahead and make yourself a basic POM file for a Bukkit plugin (Compiler plugin, resources dir, etc…), do NOT add the Jar plugin. Since our plugin requires some extra dependencies, we're going to use the Maven Shade Plugin to squash all of our dependiencies into what’s called an UberJAR.

    Add the following to your plugins section:
    HTML:
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.2</version>
        <configuration>
            <promoteTransitiveDependencies>false</promoteTransitiveDependencies>
            <minimizeJar>true</minimizeJar>
            <filters>
                <filter>
                    <artifact>*:*</artifact>
                    <excludes>
                        <exclude>META-INF/*.SF</exclude>
                        <exclude>META-INF/*.DSA</exclude>
                        <exclude>META-INF/*.RSA</exclude>
                    </excludes>
                </filter>
            </filters>
        </configuration>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
     
    
    This will generate our UberJAR and exclude certain files that we do not want (we'll talk about those later as well).

    Now, we are going to add the dependencies and repositories we need for this to work.

    HTML:
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-server</artifactId>
        <version>9.1.3.v20140225</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty.aggregate</groupId>
        <artifactId>jetty-all-server</artifactId>
        <version>7.0.2.RC0</version>
        </dependency>
    <dependency>
        <groupId>org.java-websocket</groupId>
        <artifactId>Java-WebSocket</artifactId>
        <version>1.3.0</version>
    </dependency>
    
    HTML:
    <repository>
            <id>googlecode</id>
            <name>jWebSocket Repository</name>
            <url>http://jwebsocket.googlecode.com/svn/repo</url>
    </repository>
    
    We’ll need these in a second.

    OK, Great! You have set up all the Maven we need to compile the plugin. Create a basic plugin skeleton, and test that Maven builds successfully

    Now, it’s real talk time. You've gotten this far, so you must feel some dedication to the project, so I’m going to explain the best I can how this is going to work. We are going to set up two servers inside of your plugin. That’s right. Two servers. The first one is a simple Jetty http file server. We need this to server the html, JS, sound files, etc… to the user’s web browser. Not bad eh? The next one is called a Websocket Server. We need a Websocket server to transfer real time data of what’s going on in the Bukkit world to the web browser so we can queue sounds to play. At first I was considering going with a Flash web client, with a Java based server, but I decided websocket would be better. Here’s why:
    - Websocket is new (HTML5)
    - Flash is going to die out eventually (let’s face it, we all know it’s true).
    - Flash is stuck inside of a little virtual reality where I can access nothing outside of the flash player, so I’m left with what? Crappy AS3, heh.
    - Websocket can take full advantage of the awesomeness of Javascript. The event functions are called right in your Websocket Javascript code.
    - Websocket is flexible, a websocket server can be built in any language simply because it is an upgraded version of the HTTP protocol. The handshake actually starts out as HTTP, then it gets upgraded by the server to a WS protocol.
    - Flash has a awful sound engine. We’re going to use howler.js later on.

    We’re going to create our two servers now. They will be two separate classes, and be started with a static runServer() method. It’s OK to use static methods here because the servers run on a new thread anyway.

    For our HTTP server:

    PHP:
    import java.io.File;
     
    import org.eclipse.jetty.server.Handler;
    import org.eclipse.jetty.server.Server;
    import org.eclipse.jetty.server.handler.DefaultHandler;
    import org.eclipse.jetty.server.handler.HandlerList;
    import org.eclipse.jetty.server.handler.ResourceHandler;
     
    public class 
    WebServer {
        public static 
    void runServer() {
            
    Server server = new Server(8080);
     
            
    ResourceHandler resource_handler = new ResourceHandler();
            
    resource_handler.setDirectoriesListed(true);
            
    resource_handler.setWelcomeFiles(new String[] { "index.html" });
     
            new 
    File(YourPlugin.getPlugin(YourPlugin.class).getDataFolder(), "httdocs").mkdirs();
            
    resource_handler.setResourceBase(new File(SGApi.getPlugin().getDataFolder(), "httdocs").getAbsolutePath());
     
            
    HandlerList handlers = new HandlerList();
            
    handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() });
            
    server.setHandler(handlers);
     
            try {
                
    server.start();
            } catch (
    Exception e) {
                
    e.printStackTrace();
            }
     
        }
    }
    This is going to create a very basic file server on port 8080 and run it. Don’t forget to call WebServer.runServer(); somewhere in your onEnable() method. The root directory of the server is called httdocs, located in your plugin’s data folder. We’ll add some things there later.

    Now, basically the same thing for the Websocket server:
    PHP:
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.net.UnknownHostException;
    import java.util.Collection;
     
    import org.bukkit.Bukkit;
    import org.java_websocket.WebSocket;
    import org.java_websocket.WebSocketImpl;
    import org.java_websocket.handshake.ClientHandshake;
    import org.java_websocket.server.WebSocketServer;
     
    public class 
    WebsocketServer extends WebSocketServer {
        public static 
    WebsocketServer s;
     
        public 
    WebsocketServer(int portthrows UnknownHostException {
            
    super(new InetSocketAddress(port));
        }
     
        public 
    WebsocketServer(InetSocketAddress address) {
            
    super(address);
        }
     
        @
    Override
        
    public void onOpen(WebSocket connClientHandshake handshake) {
            
    WebsocketSessionManager.getSessionManager().openSession(conn.getRemoteSocketAddress().getAddress().getHostAddress());
            
    Bukkit.getLogger().info(conn.getRemoteSocketAddress().getAddress().getHostName() + " has connected to the Websocket server!");
        }
     
        @
    Override
        
    public void onClose(WebSocket connint codeString reasonboolean remote) {
            
    WebsocketSessionManager.getSessionManager().endSession(conn.getRemoteSocketAddress().getAddress().getHostAddress());
            
    Bukkit.getLogger().info(conn " has disconnected form the Websocket server");
        }
     
        @
    Override
        
    public void onMessage(WebSocket connString message) {
            
    Bukkit.getLogger().info("Recieve Websocket packet - " conn ":" message);
            if (
    message.split(":")[0].equalsIgnoreCase("name")) {
                
    WebsocketSessionManager.getSessionManager().addSessionUsername(conn.getRemoteSocketAddress().getAddress().getHostAddress(), message.split(":")[1]);
            }
        }
     
        public static 
    void runServer() throws InterruptedExceptionIOException {
            
    WebSocketImpl.DEBUG true;
            
    int port 8887;
            
    = new WebsocketServer(port);
            
    s.start();
            
    Bukkit.getLogger().info("Websocket server started on port: " s.getPort());
        }
     
        @
    Override
        
    public void onError(WebSocket connException ex) {
            
    ex.printStackTrace();
            if (
    conn != null) {
                
    // some errors like port binding failed may not be assignable to a specific websocket
            
    }
        }
     
        public 
    void sendToAll(String data) {
            
    Collection<WebSocketcon connections();
            
    synchronized (con) {
                for (
    WebSocket c con) {
                    
    c.send(data);
                }
            }
        }
     
        public 
    void sendData(WebsocketSession sessionString data) {
            
    Collection<WebSocketcon connections();
            
    synchronized (con) {
                for (
    WebSocket c con) {
                    if (
    c.getRemoteSocketAddress().getAddress().getHostAddress().equalsIgnoreCase(session.getHost())) {
                        
    Bukkit.getLogger().info("Send data packet: " data);
                        
    c.send(data);
                    }
                }
            }
        }
    }
     
    Cool! This runs the server on port 8887, and that’s about it for the actual server class. Now you may notice that we are missing WebsocketSessionManager.java, which we will create in a second, but let me explain why we need it first. So the only useful information we can get from a Connection (a list of connections are stored in the WebsocketServer class) is the IP address of the host, but we also need the Minecraft username of the host. Now I have the Javascript set up (that you will see in a bit) to send the username of the player right as the Connection is opened. We need a place to store these usernames, and be able to link them back to their connection to send data, and that is what Sessions are for. First we will create the class WebsocketSession:
    PHP:
    public class WebsocketSession {
        
    String host;
        
    String name;
     
        public 
    WebsocketSession(String host) {
            
    this.host host;
        }
     
        public 
    String getHost() {
            return 
    host;
        }
     
        public 
    String getName() {
            return 
    name;
        }
     
        public 
    void setName(String name) {
            
    this.name name;
        }
     
        public 
    String toString() {
            return 
    "WebsocketSession.java - Host: " host " Name: " name;
        }
    }
    Now this is simply a data storage class, nothing fancy here. We will be storing a list of these in our session manager, each WebsocketSession is to represent an active Websocket connection. So now let’s get our session manager rolling. It’s not really that complicated, just a bunch of tools for adding, removing, and getting entries in the session list.
    (I am aware this class uses double-checked locking, but this tutorial is already too long, we have to move forward)
    Here it is:
    PHP:
    import java.util.ArrayList;
    import java.util.List;
     
    import org.bukkit.Bukkit;
     
    public class 
    WebsocketSessionManager {
        private static 
    WebsocketSessionManager sessionManager;
     
        private List<
    WebsocketSessionsessions = new ArrayList<WebsocketSession>();
     
        public static 
    WebsocketSessionManager getSessionManager() {
            if (
    sessionManager == null) {
                
    sessionManager = new WebsocketSessionManager();
            }
            return 
    sessionManager;
        }
     
        public List<
    WebsocketSessiongetSessions() {
            return 
    sessions;
        }
     
        public 
    void openSession(String host) {
            
    sessions.add(new WebsocketSession(host));
            
    Bukkit.getLogger().info("Opened Websocket session: " getSessionByHost(host));
        }
     
        public 
    void endSession(String host) {
            
    sessions.remove(getSessionByHost(host));
        }
     
        public 
    void endSessionByName(String name) {
            
    sessions.remove(getSessionByName(name));
        }
     
        public 
    WebsocketSession getSessionByHost(String host) {
            for (
    WebsocketSession s sessions) {
                if (
    s.getHost() == host)
                    return 
    s;
            }
            return 
    null;
        }
     
        public 
    WebsocketSession getSessionByName(String name) {
            for (
    int i 0sessions.size(); i++) {
                
    Bukkit.getLogger().info("Session gotten:" sessions.get(i));
                if (
    sessions.get(i).getName().equalsIgnoreCase(name))
                    return 
    sessions.get(i);
            }
            return 
    null;
        }
     
        public 
    void addSessionUsername(String hostString name) {
            
    Bukkit.getLogger().info("Attemption to update session with data: " name " and a host of: " host);
            for (
    int i 0sessions.size(); i++) {
                if (
    sessions.get(i).getHost().equalsIgnoreCase(host)) {
                    
    sessions.get(i).setName(name);
                    
    Bukkit.getLogger().info("Updated Websocket session information: " sessions.get(i));
                }
            }
        }
    }
    At this point, compile (with maven) take the Jar in your target/ directory (the directory where the project and POM file is) and run it on a CB server. If it crashes, look over your code a bit.

    Continued in post #1

    So now we’ve basically got all we need to make this work! We’ll come back here eventually to actually play some sound, but for now, let’s shift gears a bit. We are going to be looking into the client side of things.

    First, we are going to create a simple index.html file as a container to deliver our scripts in. Use this one exactly:
    HTML:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
          <script language="javascript" type="text/javascript" src="howler.js"></script>
      </head>
      <body>
          <FORM NAME="session">
            <INPUT TYPE="hidden" NAME="name" SIZE="35">
          </form>
          <script language="javascript" type="text/javascript" src="websocket.js"></script>
      </body>
    </html>
    
    I’ll explain the invisible form in a minute.

    So as you can see, this is just a very simple script container, after you’ve got it working, feel free to add any style to this page that you want.

    Save the file as index.html and drop it right into your httdocs folder, located in your plugin folder.

    At this point, it would be a good time to drop our audio class in the httdocs folder. We will be using howler.js audio. Its really awesome. Just drop the howler.js file into your httdocs folder. You can download the latest version here: https://github.com/goldfire/howler.js/

    Now we’re going to write our own Javascript called Websocket.js. It will establish a websocket connection, sent the username of the player, listen for incoming events, and play the corresponding sound file located in the httdocs file.
    PHP:
    var name window.location
    document
    .session.name.value name
     
    var text document.session.name.value
     
    var ws = new WebSocket("ws://" window.location.hostname ":8887/");
     
    ws.onopen = function () {
     
        if (
    name != null) {
            
    document.write("Connected to websocket server! <br>");
            
    ws.send("name:" delineate(text));
            
    document.write("Sent data: name:" delineate(text) + "<br>");
        }
     
    };
     
    ws.onmessage = function (evt) {
        var 
    sound = new Howl({
            
    urls: ['sounds/' evt.data '.ogg']
        }).
    play();
    };
     
    ws.onclose = function () {
        
    alert("Closed!");
    };
     
    ws.onerror = function (err) {
        
    alert("Error: " err);
    };
     
    function 
    delineate(str) {
        
    theleft str.indexOf("=") + 1;
        
    theright str.lastIndexOf("&");
        return (
    str.substring(thelefttheright));
    }
    So what we have done here is included data in the URL that you access the page from. So once this is running you could go to http://localhost:8080/index.html?name=Jonthespartan29&sessionId=null and it would send your name to the server, and associate it with the connection you established in the SessionManager.

    Here would be a good place to note that we are going to use OGG Vorbis files for the sound and here’s why:
    - Its really fast
    - The files are small
    - The quality is high
    - Its cooler to say you use OGG Vorbis as opposed to MP3.

    Also: Your OGG files must be encoded CORRECTLY! Most sound converters do not do this. If you want to convert to OGG, I recommend Adobe Media Encoder, but most sound editors that actually reencode the sound should be fine.

    I’ll attach the file I’m working with in this post.

    So our file in names play.ogg. Make a new folder in the httdocs folder called “sounds”, and copy play.ogg to that folder.

    You're done with the client now! Let’s step back into our plugin and play that sound.

    We’re actually going to create a new class called SoundEffectsManager to send the data, in case our protocol changes in the future, we only need to change SoundEffectsManager.java as opposed to everywhere a sound is played.
    PHP:
    import org.bukkit.Bukkit;
    import org.bukkit.entity.Player;
     
    public class 
    SoundEffectsManager {
        public static 
    void playToPlayer(Player pString data) {
            if (
    WebsocketSessionManager.getSessionManager().getSessionByName(p.getName()) != null) {
                
    WebsocketServer.s.sendData(WebsocketSessionManager.getSessionManager().getSessionByName(p.getName()), data);
            }
        }
     
        public static 
    void playToAll(String data) {
            for (
    Player p Bukkit.getOnlinePlayers()) {
                if (
    WebsocketSessionManager.getSessionManager().getSessionByName(p.getName()) != null) {
                    
    WebsocketServer.s.sendData(WebsocketSessionManager.getSessionManager().getSessionByName(p.getName()), data);
                }
            }
        }
    }
    Nothing too bad here. We’re just retrieving the session of that player from the SessionManager, and playing the file named what you pass as the data field. So if we wanted to play play.ogg from earlier, we would pass “play” as data, without the “.ogg” ending, as our JS does that.

    Ending notes:
    It would be helpful to give the player a URL on logon, so you could do something like this on the onPlayerJoin event:
    PHP:
    p.sendMessage(ChatColor.WHITE "" ChatColor.BOLD "▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮");
    p.sendMessage(ChatColor.AQUA "");
    p.sendMessage(ChatColor.GREEN "" ChatColor.BOLD "Want to here LIVE music, announcers, and sound effects?");
    p.sendMessage(ChatColor.AQUA "");
    p.sendMessage(ChatColor.AQUA "" ChatColor.BOLD "Click this link:");
    p.sendMessage(ChatColor.WHITE "" ChatColor.UNDERLINE "http://" Bukkit.getServer().getServerIP() + ":8080/index.html?name=" p.getName() + "&sessionId=" + new Random().nextInt(10000));
    p.sendMessage(ChatColor.AQUA "");
    p.sendMessage(ChatColor.DARK_RED "" ChatColor.BOLD "Simply leave your browser window open in the background, turn up your speakers, and we'll do the rest!");
    p.sendMessage(ChatColor.AQUA "");
    p.sendMessage(ChatColor.WHITE "" ChatColor.BOLD "▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮■▮");
     
    FAQ:

    Q: I'm getting like 50 "NoClassDefFoundErrors" when I try to test the plugin and I'm about to throw my computer at a wall so please help me!
    A: You MUST be using a maven compiler (with M2E this is located under run, not export) and you MUST be running the goals "clean package" and note that "clean jar" won't work as that is for projects without shade that do not need packaged dependencies.

    Q: Why aren't my server's starting at all AHHHHHHHHHHHHHHH!
    A: Make sure you're calling the runServer() method for both of the servers in your onEnable.


    I hope you liked my tutorial and find this information useful. Post below if you run into any issues please. (Or if I have forgotten something)

    The source file I used in this tutorial: http://ge.tt/6GhWupT1/v/0
     
    Last edited by a moderator: Feb 20, 2016
    MarinD99, Goblom, Concurrent and 18 others like this.
  2. Quantum64
    There's an XML syntax for a reason :p

    SOO.... THIS is what you have been working on in CMSG :O
     
    TigerHix likes this.
  3. Awesome! Thanks dude :D
     
    Quantum64 likes this.
  4. Offline

    Quantum64

    It ended up working so well I decided to make a tutorial so yeah :D

    Did you get it working OK?
     
  5. interesting! i'Ve been wanting to do some custom sound stuff on my server, i skimmed the thread for now but i'll have to come back and actually read it more. Unless of course someone is already working on something similar! Was thinking about having positional sound system where like as you enter cities you can hear music playing and sounds of crowds that kinda stuff and as you get out into the wilderness it turns to more country like sounds.
     
  6. Offline

    Quantum64

    Well the point of me making this was not really to give you the source code or a compiled plugin, but more to teach you how to implement this into your own plugin using new, efficient technologies. Anyway your description of what you want to do seems a perfect use for this code.

    Are you trying to say something here?

    Your first post ever on the Bukkit forums and your criticizing someone's work... Interesting.
     
  7. Awesome tut!
    (By the way, The Hive wasn't the first one to do it. DansArcade was.)
     
  8. of course not hehe, i was just putting it out there that way if someone happened to see this thread and was working on something similar i wasn't wasting my time haha.
     
  9. Offline

    Quantum64

    I see what you mean, but if I were to run a server, I would develop all my own plugins XD.
     
  10. Quantum64
    Nice tutorial dude!

    Now i ended up thinking what would be posible by using websockets combined with bukkit....

    and i thought it would be cool to use the websocket server to manage VoIP connections between players so they have a local area voice chat would be cool with this plugin i have seen years ago where you must be "connectet2 to a "mobile phone system" to chat...

    I definitly will have a look at this ;D
     
  11. I keep getting this error in my pom.xml
    Missing artifact org.eclipse.jetty:jetty-server:jar:9.1.3.v20140225

    Heres my pom.xml:
    Code:xml
    1. <project xmlns="[url]http://maven.apache.org/POM/4.0.0[/url]" xmlns:xsi="[url]http://www.w3.org/2001/XMLSchema-instance[/url]"
    2. xsi:schemaLocation="[url]http://maven.apache.org/POM/4.0.0[/url] [url]http://maven.apache.org/xsd/maven-4.0.0.xsd[/url]">
    3. <modelVersion>4.0.0</modelVersion>
    4.  
    5. <groupId>AudioPluginTest</groupId>
    6. <artifactId>apt</artifactId>
    7. <version>0.0.1-SNAPSHOT</version>
    8. <packaging>jar</packaging>
    9.  
    10. <name>apt</name>
    11. <url>[url]http://maven.apache.org</url>[/url]
    12.  
    13. <properties>
    14. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    15. </properties>
    16.  
    17. <build>
    18. <plugins>
    19. <plugin>
    20. <groupId>org.apache.maven.plugins</groupId>
    21. <artifactId>maven-shade-plugin</artifactId>
    22. <version>2.2</version>
    23. <configuration>
    24. <promoteTransitiveDependencies>false</promoteTransitiveDependencies>
    25. <minimizeJar>true</minimizeJar>
    26. <filters>
    27. <filter>
    28. <artifact>*:*</artifact>
    29. <excludes>
    30. <exclude>META-INF/*.SF</exclude>
    31. <exclude>META-INF/*.DSA</exclude>
    32. <exclude>META-INF/*.RSA</exclude>
    33. </excludes>
    34. </filter>
    35. </filters>
    36. </configuration>
    37. <executions>
    38. <execution>
    39. <phase>package</phase>
    40. <goals>
    41. <goal>shade</goal>
    42. </goals>
    43. </execution>
    44. </executions>
    45. </plugin>
    46.  
    47. <plugin>
    48. <groupId>org.apache.maven.plugins</groupId>
    49. <artifactId>maven-compiler-plugin</artifactId>
    50. <configuration>
    51. <source>1.7</source>
    52. <target>1.7</target>
    53. </configuration>
    54. </plugin>
    55. </plugins>
    56. </build>
    57.  
    58. <dependencies>
    59. <dependency>
    60. <groupId>org.eclipse.jetty</groupId>
    61. <artifactId>jetty-server</artifactId>
    62. <version>9.1.3.v20140225</version>
    63. </dependency>
    64. <dependency>
    65. <groupId>org.eclipse.jetty.aggregate</groupId>
    66. <artifactId>jetty-all-server</artifactId>
    67. <version>7.0.2.RC0</version>
    68. </dependency>
    69. <dependency>
    70. <groupId>org.java-websocket</groupId>
    71. <artifactId>Java-WebSocket</artifactId>
    72. <version>1.3.0</version>
    73. </dependency>
    74. <dependency>
    75. <groupId>org.bukkit</groupId>
    76. <artifactId>bukkit</artifactId>
    77. <version>1.7.5-R0.1-SNAPSHOT</version>
    78. <type>jar</type>
    79. <scope>provided</scope>
    80. </dependency>
    81. </dependencies>
    82.  
    83. <repositories>
    84. <repository>
    85. <id>bukkit-repo</id>
    86. <url>[url]http://repo.bukkit.org/content/groups/public/</url>[/url]
    87. </repository>
    88. </repositories>
    89.  
    90. </project>
    91.  

    Any idea to fix this? Please Help
     
  12. Offline

    Quantum64

    I just realised I forgot the jWebSocket repository, its in the Maven section of the tutorial now, you need to all that. As for your issue, are you using M2E for Eclipse? If so right click your project, go to the Maven submenu, and click update project dependencies. See if that helps.
     
  13. I keep getting the following error when attempting to run Webserver.runServer():
    java.lang.NoClassDefFoundError: org/eclipse/jetty/server/Handler
    at Me.myplugin.mymainclass.onEnable(mymainclass.java:248) ~[?:?]
    at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:250) ~[spigot.jar:git-Spigot-1.7.2-R0.3-122-gb58e277]
    at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:350) [spigot.jar:git-Spigot-1.7.2-R0.3-122-gb58e277]
    at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:390) [spigot.jar:git-Spigot-1.7.2-R0.3-122-gb58e277]
    at org.bukkit.craftbukkit.v1_7_R1.CraftServer.loadPlugin(CraftServer.java:460) [spigot.jar:git-Spigot-1.7.2-R0.3-122-gb58e277]
    at org.bukkit.craftbukkit.v1_7_R1.CraftServer.enablePlugins(CraftServer.java:380) [spigot.jar:git-Spigot-1.7.2-R0.3-122-gb58e277]
    at net.minecraft.server.v1_7_R1.MinecraftServer.m(MinecraftServer.java:348) [spigot.jar:git-Spigot-1.7.2-R0.3-122-gb58e277]
    at net.minecraft.server.v1_7_R1.MinecraftServer.g(MinecraftServer.java:325) [spigot.jar:git-Spigot-1.7.2-R0.3-122-gb58e277]
    at net.minecraft.server.v1_7_R1.MinecraftServer.a(MinecraftServer.java:281) [spigot.jar:git-Spigot-1.7.2-R0.3-122-gb58e277]
    at net.minecraft.server.v1_7_R1.DedicatedServer.init(DedicatedServer.java:186) [spigot.jar:git-Spigot-1.7.2-R0.3-122-gb58e277]
    at net.minecraft.server.v1_7_R1.MinecraftServer.run(MinecraftServer.java:437) [spigot.jar:git-Spigot-1.7.2-R0.3-122-gb58e277]
    at net.minecraft.server.v1_7_R1.ThreadServerApplication.run(SourceFile:617) [spigot.jar:git-Spigot-1.7.2-R0.3-122-gb58e277]
     
  14. Offline

    Quantum64

    Did you build with Maven? It appears the dependencies were left out of the JAR altogether.
     
  15. Didn't seem to work I'm getting the same error. Where now? It was working fine the other day when I first used this resource.
     
  16. Offline

    Quantum64

  17. Offline

    Quantum64

    Jellal Fernandes Yes, if you want you can PM me your pom and I will check it over for errors, but I assure you the dependencies are all still valid, but you may have the scope set incorrectly.
     
  18. YES!!! Finally got it to stop with the error after copying the stuff from your pom.xml that I needed. This is also why I don't work with maven so much because no doubt I'll find a way to cause a problem :/

    *EDIT* I give up it gave me another error *slams the door on maven's face*
     
  19. Offline

    Quantum64

    Do you have the compiler plugin? Also make sure you didn't copy the site or assembly plugins from the POM I gave you.
     
  20. Probably easier to talk to you when your online or something maybe you could help me then, see if it's my computer being stupid or if I'm being stupid.
     
  21. Code:
    [Server] ERROR Error occurred while enabling GGApi v1.0 (Is it up to date?)
    [Server] [Informatie] java.lang.NoClassDefFoundError: org/eclipse/jetty/server/Handler
    [Server] [Informatie] at net.goldguard.api.API.onEnable(API.java:55) ~[?:?]
    [Server] [Informatie] at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:250) ~[cbdev1.7.8.jar:git-Bukkit-1.7.2-R0.3-59-g6efeddf-b3074jnks]
    [Server] [Informatie] at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:324) [cbdev1.7.8.jar:git-Bukkit-1.7.2-R0.3-59-g6efeddf-b3074jnks]
    [Server] [Informatie] at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:404) [cbdev1.7.8.jar:git-Bukkit-1.7.2-R0.3-59-g6efeddf-b3074jnks]
    [Server] [Informatie] at org.bukkit.craftbukkit.v1_7_R3.CraftServer.loadPlugin(CraftServer.java:448) [cbdev1.7.8.jar:git-Bukkit-1.7.2-R0.3-59-g6efeddf-b3074jnks]
    [Server] [Informatie] at org.bukkit.craftbukkit.v1_7_R3.CraftServer.enablePlugins(CraftServer.java:382) [cbdev1.7.8.jar:git-Bukkit-1.7.2-R0.3-59-g6efeddf-b3074jnks]
    [Server] [Informatie] at net.minecraft.server.v1_7_R3.MinecraftServer.n(MinecraftServer.java:352) [cbdev1.7.8.jar:git-Bukkit-1.7.2-R0.3-59-g6efeddf-b3074jnks]
    [Server] [Informatie] at net.minecraft.server.v1_7_R3.MinecraftServer.g(MinecraftServer.java:326) [cbdev1.7.8.jar:git-Bukkit-1.7.2-R0.3-59-g6efeddf-b3074jnks]
    [Server] [Informatie] at net.minecraft.server.v1_7_R3.MinecraftServer.a(MinecraftServer.java:282) [cbdev1.7.8.jar:git-Bukkit-1.7.2-R0.3-59-g6efeddf-b3074jnks]
    [Server] [Informatie] at net.minecraft.server.v1_7_R3.DedicatedServer.init(DedicatedServer.java:182) [cbdev1.7.8.jar:git-Bukkit-1.7.2-R0.3-59-g6efeddf-b3074jnks]
    [Server] [Informatie] at net.minecraft.server.v1_7_R3.MinecraftServer.run(MinecraftServer.java:436) [cbdev1.7.8.jar:git-Bukkit-1.7.2-R0.3-59-g6efeddf-b3074jnks]
    [Server] [Informatie] at net.minecraft.server.v1_7_R3.ThreadServerApplication.run(SourceFile:628) [cbdev1.7.8.jar:git-Bukkit-1.7.2-R0.3-59-g6efeddf-b3074jnks]
    [Server] [Informatie] Caused by: java.lang.ClassNotFoundException: org.eclipse.jetty.server.Handler
    [Server] [Informatie] at java.net.URLClassLoader$1.run(URLClassLoader.java:366) ~[?:1.7.0_21]
    [Server] [Informatie] at java.net.URLClassLoader$1.run(URLClassLoader.java:355) ~[?:1.7.0_21]
    [Server] [Informatie] at java.security.AccessController.doPrivileged(Native Method) ~[?:1.7.0_21]
    [Server] [Informatie] at java.net.URLClassLoader.findClass(URLClassLoader.java:354) ~[?:1.7.0_21]
    [Server] [Informatie] at org.bukkit.plugin.java.PluginClassLoader.findClass(PluginClassLoader.java:77) ~[cbdev1.7.8.jar:git-Bukkit-1.7.2-R0.3-59-g6efeddf-b3074jnks]
    [Server] [Informatie] at org.bukkit.plugin.java.PluginClassLoader.findClass(PluginClassLoader.java:62) ~[cbdev1.7.8.jar:git-Bukkit-1.7.2-R0.3-59-g6efeddf-b3074jnks]
    [Server] [Informatie] at java.lang.ClassLoader.loadClass(ClassLoader.java:423) ~[?:1.7.0_21]
    [Server] [Informatie] at java.lang.ClassLoader.loadClass(ClassLoader.java:356) ~[?:1.7.0_21]
    
    Start with this:
    PHP:
    WebServer.runServer(this);
    System.out.println("Webserver enabled!");
    WebServer class (the startup void is a bit different, as I needed a reference to the mainclass):
    PHP:
    package net.goldguard.api.audioserver;

    import java.io.File;

    import net.goldguard.api.API;

    import org.eclipse.jetty.server.Handler;
    import org.eclipse.jetty.server.Server;
    import org.eclipse.jetty.server.handler.DefaultHandler;
    import org.eclipse.jetty.server.handler.HandlerList;
    import org.eclipse.jetty.server.handler.ResourceHandler;

    public class 
    WebServer {
        public static 
    void runServer(API MainClass) {
            
    Server server = new Server(8187);
            
            
    ResourceHandler resource_handler = new ResourceHandler();
            
    resource_handler.setDirectoriesListed(true);
            
    resource_handler.setWelcomeFiles(new String[] { "index.html" });
            
            new 
    File(MainClass.getDataFolder(), "httdocs").mkdirs();
            
    resource_handler.setResourceBase(new File(MainClass.getDataFolder(), "httdocs").getAbsolutePath());
            
            
    HandlerList handlers = new HandlerList();
            
    handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() });
            
    server.setHandler(handlers);
            
            try {
                
    server.start();
            } catch (
    Exception e) {
                
    e.printStackTrace();
            }
        }
    }
    Seems like a Jetty class is missing, but I've installed Maven and no errors in code.

    pom.xml:
    Code:
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>gg-api</groupId>
      <artifactId>gg-api</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>jar</packaging>
      <name>gg-api</name>
      <url>http://maven.apache.org</url>
      <description>API For GoldGuardMC</description>
      <properties>
    	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      </properties>
      <build>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
          <plugin>
    		<groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
              <source>1.7</source>
              <target>1.7</target>
            </configuration>
          </plugin>
    	  <plugin>
    		<groupId>org.apache.maven.plugins</groupId>
    		<artifactId>maven-shade-plugin</artifactId>
    		<version>2.2</version>
    		<configuration>
    			<promoteTransitiveDependencies>false</promoteTransitiveDependencies>
    			<minimizeJar>true</minimizeJar>
    			<filters>
    				<filter>
    					<artifact>*:*</artifact>
    					<excludes>
    						<exclude>META-INF/*.SF</exclude>
    						<exclude>META-INF/*.DSA</exclude>
    						<exclude>META-INF/*RSA</exclude>
    					</excludes>
    				</filter>
    			</filters>
    		</configuration>
    		<executions>
    			<execution>
    				<phase>package</phase>
    				<goals>
    					<goal>shade</goal>
    				</goals>
    			</execution>
    		</executions>
    	  </plugin>
        </plugins>
      </build>
      <dependencies>
    	<dependency>
    		<groupId>org.eclipse.jetty</groupId>
    		<artifactId>jetty-server</artifactId>
    		<version>9.1.3.v20140225</version>
    	</dependency>
    	<dependency>
    		<groupId>org.eclipse.jetty.aggregate</groupId>
    		<artifactId>jetty-all-server</artifactId>
    		<version>7.0.2.RC0</version>
    	</dependency>
    	<dependency>
    		<groupId>org.java-websocket</groupId>
    		<artifactId>Java-WebSocket</artifactId>
    		<version>1.3.0</version>
    	</dependency>
      </dependencies>
      <repositories>
    	<repository>
    		<id>googlecode</id>
    		<name>jWebSocket Repository</name>
    		<url>http://jwebsocket.googlecode.com/svn/repo</url>
    	</repository>
      </repositories>
    </project>
    
    Quantum64 : Do you know what's wrong?
     
  22. Offline

    Quantum64

    rcth What goals are you using for executing Maven?

    Also open up the jar with a zip utility and see if there's an org.eclipse folder at all.
     
  23. Quantum64 I don't see any org.eclipse folder in my exported jar. And what do you mean with goals? I only installed Maven on the project because this tutorial needed Maven.
     
  24. Offline

    Quantum64

    You need to actually build the project with maven too, should be in the run menu if your using M2E, anyway build it with the goals "clean package"
     
  25. I used Run As -> Maven Clean, it said build succesful, but in the /target folder, I can't find the .jar. And normal export doesn't work (class files on classpath not found or not accessible for: )
     
  26. Offline

    Quantum64

    rcth
    Maven clean, then Maven package
     
  27. Quantum64 Finally got it working turns out eclipse was derping with maven so I switched over to IntelliJ. Also I think you may have forgot to mention starting the WebsocketServer because that's where I kept getting an error due to connection. Other then that great tutorial! :D
     
  28. Quantum64
    Code:
    SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
    SLF4J: Defaulting to no-operation (NOP) logger implementation
    SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
    [INFO] Scanning for projects...
    [INFO]                                                                         
    [INFO] ------------------------------------------------------------------------
    [INFO] Building gg-api 1.0.0
    [INFO] ------------------------------------------------------------------------
    Downloading: http://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-install-plugin/2.3.1/maven-install-plugin-2.3.1.pom
    Downloaded: http://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-install-plugin/2.3.1/maven-install-plugin-2.3.1.pom (5 KB at 14.8 KB/sec)
    [INFO] 
    [INFO] --- maven-resources-plugin:2.5:resources (default-resources) @ gg-api ---
    [debug] execute contextualize
    [WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory C:\Users\Thimo\git\gg-api\src\main\resources
    [INFO] 
    [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ gg-api ---
    [INFO] Changes detected - recompiling the module!
    [INFO] Compiling 32 source files to C:\Users\Thimo\git\gg-api\target\classes
    [INFO] -------------------------------------------------------------
    [ERROR] COMPILATION ERROR : 
    [INFO] -------------------------------------------------------------
    [ERROR] No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?
    [INFO] 1 error
    [INFO] -------------------------------------------------------------
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD FAILURE
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 2.868s
    [INFO] Finished at: Sat May 03 08:31:07 CEST 2014
    [INFO] Final Memory: 9M/165M
    [INFO] ------------------------------------------------------------------------
    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project gg-api: Compilation failure
    [ERROR] No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?
    [ERROR] -> [Help 1]
    [ERROR] 
    [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
    [ERROR] Re-run Maven using the -X switch to enable full debug logging.
    [ERROR] 
    [ERROR] For more information about the errors and possible solutions, please read the following articles:
    [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
    
     
  29. Do you have JDK installed? If you don't I think you need to install it and make sure it's the latest version.
     
Thread Status:
Not open for further replies.

Share This Page