[Tutorial] Handling data through multiple servers.

Discussion in 'BungeeCord Plugin Development' started by dillyg10, Mar 8, 2013.

Thread Status:
Not open for further replies.
  1. There is often times when you need to relay data from server to server. Basically, there are two ways of doing this, Plugin messaging, and sockets. There are pros, and cons, to each method:

    Plugin messaging:
    Pros:
    • Requires little setup on your part
    • Already pre-built api in Bungee/Bukkit
    • Does not require you to open up a seperate port.
    Cons:
    • REQUIRES AT LEAST ONE PLAYER!
    The fact that it does require 1 player in my mind is a huge con.
    Sockets:
    Pros:
    • Your handle your own data, meaning that it's all you, no middle man
    • Does not require ANY players!
    • You can essentially use this from anywhere on earth, so you can send data to the socket to the socket from your computer
    Cons:
    • A tad complicated to setup
    • Requires you to open a port (you will need to forward it if your not connection from localhost)
    • Can be inefficient if you don't handle the data right.
    So, I'm going to go through each method and how to do it:
    We are going to have 2 programs, for messaging when the user types /broadcast, it will say something to everyone on the current server [NOTE: This can possibly be a poor example becuase you can use BungeeAPI to do this, but whatever ^_^]. The second, 5 seconds after the main server starts it will send a message to one of the servers "HI!".
    Messaging:
    There is a fantastic sticky on messaging in this section, I would reccomend reading it. This is going to be a bit more focussed on putting a plugin on the proxy, and reading/sending data through that, than a lot of the Bukkit side.
    There are a few things you need to setup before you start, firstly we're going to go to Bukkit. In your onEnable you need to put:
    Code (Text):

    Bukkit.getMessenger().registerOutgoingPluginChannel(this, "Your channle");
     
    Now that you have that done, your pretty much done Bukkit side (until we actually send data)
    Next, is the Bungee plugin side, here is some skeleton code we are going to work with:
    Code (Text):

    public class HubPlugin extends Plugin implements Listener {
        public void onEnable(){
            //Register the channel and listener
            BungeeCord.getInstance().registerChannel("Hub");
            BungeeCord.getInstance().getPluginManager().registerListener(this);
     
        }
     
        //This is the actual "Event", it'll be called when a plugin message is recieved
        @Subscribe
        public void onMessageRecieve(PluginMessageEvent e){
            if (e.getTag().equals("Hub")){
                //DOOOO stuff!
            }
           
        }
     
       //Send message to a server
        public void sendMessageToServer(String msg, String server){
            ServerInfo si =  ProxyServer.getInstance().getServerInfo(server);
            for (ProxiedPlayer p : si.getPlayers()){
                p.sendMessage(msg);
            }
        }
    }
     
    with that, we are now going to register the bukkit command.

    Code (Text):

    public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
            if (label.equalsIgnoreCase("broadcast")){
                //Setup a way to write the data
                ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                DataOutputStream datastream = new DataOutputStream(bytes);
                try {
                    //Write the data
                    datastream.writeUTF("Hi!");
                    //Send the data to the player
                    ((Player)sender).sendPluginMessage(this, "Hub", bytes.toByteArray());
                    //...profit?
                } catch (IOException e) {
                    //shutup datastream
                }
                return true;
            }
            return false;
        }
     
    Now it's time for Bungee listener.
    Code (Text):
    @Subscribe
        public void onMessageRecieve(PluginMessageEvent e){
            //Check if the channel is Hub
            if (e.getTag().equals("Hub")){
                //read the data
                DataInputStream di = new DataInputStream(new ByteArrayInputStream(e.getData()));
                try {
                    //This assumes that the server is lobby,
                    //obviously you could just send more data with something like server
                    sendMessageToServer(di.readUTF(),"lobby");
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
     
        }
    That's it, for plugin messaging, now for sockets.
    Sockets:
    Sockets sockets sockets! Before we can code with sockets, we need to understand sockets.
    Basically, sockets are places where you read/write data... that's the easiest way to explain it. If you want more detailed info, I would suggest you google it :p.
    There are 2 classes in java.net associated with Sockets
    Socket.java - What you'll use on the client
    SocketServer.java - What you'll use on the server
    Firstly, we are going to setup the server socket, do this in your BungeePlugin class.
    Code (Text):

    static Socket sock;
    public void onEnable(){
      //The 1337 = port number
      sock = new ServerSocket(1337);
    }
     
    The trick with server sockets is they must ALWAYS be open, until the server shuts down. If they are not open, you will get an error. In our Bukkit project, we are going to make a method to write data to the socket.
    Code (Text):
    public static void sendDataToSocket(String data){
            Socket client;
            try {
                            //You must open the client socket EACH time you use it
                client = new Socket("localhost",1337);
                            //Use the same method as plugin messaging for sending data.
                DataOutputStream ds = new DataOutputStream(client.getOutputStream());
                ds.writeUTF(data);
                ds.close();
                client.close();
            } catch (UnknownHostException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
               
                e1.printStackTrace();
            }
        }
    Now, finally, we need to add a listener for the data. If you don't know about threading, google it!
    Code (Text):
    class ReadThread extends Thread{
            public void run(){
                while (true){
                    try {
                                            //init the client
                        client = sock.accept();
                                            //Read the data
                        DataInputStream dis = new DataInputStream(client.getInputStream());
                            String data = dis.readUTF();
                            sendMessageToServer(dat.split("/")[0],dat.split("/")[1]);
                       
     
                        dis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    Then just init the thread... and your done.
    Obviously, if you wanna go with the full example, scheduel a task when the server starts, and send the message.
    If you have any quesitons, please ask!
     
    • Informative Informative x 8
    • Funny Funny x 1
  2. You know what would be truly awesome ? A bungee/bukkit library that would abstract all this into one "BungeeSocket" class, that automatically delegated to using the best method (plugin message if a player is online, otherwise socket connection).
     
    • Agree Agree x 2
  3. It would be nice if it did something like this TBH, I think it would be really nice if the Bungee API proviced some sort of Socket class to handle socket data. I might see what I can do :p.
     
  4. Well, I did hear somewhere that a bukkit plugin was in the works for easier bungee-bukkit communication. Can't remember where though.
     
  5. Favorlock

    Sponsor

    Wasn't md_5 planning to work on a plugin called Trampoline or something?

    Also, I can't get this tutorial to work at all... I followed it to the letter.
     
    #5 Favorlock, Mar 9, 2013
    Last edited: Mar 9, 2013
  6. ah yes, that's what it was called. I wonder where it's at ?
     
  7. Favorlock

    Sponsor

    He said he hasn't even started on it yet. Btw, have you managed to get the messaging system to work? I can't get it to work even following this tutorial exactly.
     
  8. I should have some working code in a branch of BungeeBan with working messaging system, but I'm not too sure of how work-able it actually is. Make sure you register the channel in the BungeeCord plugin with ProxyServer.getInstance().registerChannel(); (I think).
     
  9. md_5

    Administrator Developer

    Yeah, its all coming pretty soon. Currently knee deep in a huge rewrite of the core before I work on that.
     
  10. Sry... i didn't see this thread. But i did write a communication plugin for bukkit.
    I think it's pretty easy to use... ^^'
     
  11. Favorlock

    Sponsor

    Apparently, according to md_5, you can't communicate plugin messages during a PlayerJoinEvent, but he gave me a work around, so now I've successfully confirmed that I am able to import vault prefixes and suffixes. I'll work on writing something that any developer can use.
     
    • Friendly Friendly x 1
  12. What problems have you been having?
     
  13. Favorlock

    Sponsor

    Already managed to get everything working thanks to md_5. See my previous post.
     
Thread Status:
Not open for further replies.