Skip to content

Custom Messages

Trevor Flynn edited this page Jan 15, 2021 · 2 revisions

Message Intro

Monkey-Netty was designed around using custom messages that make it easy to send and receive data between the server and client. To accomplish this Monkey-Netty contains the NetworkMessage interface which can be implemented to create custom messages. In fact, all internal Monkey-Netty messages also use the NetworkMessage interface.

Getting Started

To get started with creating a custom message, create a new class implementing NetworkMessage

public class TestUDPMessage implements NetworkMessage {

    @Override
    public String getName() {
        return "Test UDP Message";
    }

    @Override
    public NetworkProtocol getProtocol() {
        return NetworkProtocol.UDP;
    }
}

Here we have created a new message, DONE!. Although our message does not contain any data, we can send and receive it between the server and client. First, in this message, we have the getName() function. This is a name reference for the application, it is not used in any Monkey-Netty internal logic and does not need to be unique. The second function here is getProtocol(), this is used to tell Monkey-Netty how the message should be sent. When Monkey-Netty serializes the message to send it, only variables will be included, and a unique ID to identify the message. That means things stored in functions will be excluded, such as the getName() function.

This message serialized looks like:

         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 00 00 0a 05 73 72 01 00 00 00 00 78 70       |.....sr.....xp  |
+--------+-------------------------------------------------+----------------+

Adding Variables

Most messages we probably want to pass some variables to the client.

To add variable data, simple create a variable. It is recommended to make the variable private and use the java setter/getter model.

public class TestUDPMessage implements NetworkMessage {

    private String someValue;

    @Override
    public String getName() {
        return "Test UDP Message";
    }

    @Override
    public NetworkProtocol getProtocol() {
        return NetworkProtocol.UDP;
    }

    public String getSomeValue() {
        return someValue;
    }

    public void setSomeValue(String someValue) {
        this.someValue = someValue;
    }
}

Here our message now contains a string. If we store the string "Hello Monkey-Netty" in it, it now is serialized like this:

         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 00 00 1f 05 73 72 01 00 00 00 00 78 70 74 00 |.....sr.....xpt.|
|00000010| 12 48 65 6c 6c 6f 20 4d 6f 6e 6b 65 79 2d 4e 65 |.Hello Monkey-Ne|
|00000020| 74 74 79                                        |tty             |
+--------+-------------------------------------------------+----------------+

Advanced Messages

Sometimes we want to send complex data in our message. Messages can contain any objects that implement Serializable. For example, here we are sending an object that contains an entire HashMap and all of its contents:

public class TestTCPBigMessageB implements NetworkMessage {

    private TestSerializableDataB objectB;

    public TestTCPBigMessageB() {
        setObjectB(new TestSerializableDataB());
    }
    
    @Override
    public String getName() {
        return "Test TCP Big Message B";
    }

    @Override
    public NetworkProtocol getProtocol() {
        return NetworkProtocol.TCP;
    }
    
    @Override
    public String toString() {
        return getObjectB().toString();
    }

    public TestSerializableDataB getObjectB() {
        return objectB;
    }

    public void setObjectB(TestSerializableDataB objectB) {
        this.objectB = objectB;
    }
}

public class TestSerializableDataB implements Serializable {

    private HashMap<String, Object> map = new HashMap<>();

    public TestSerializableDataB() {
        map.put("test1", 12);
        map.put("test2", "TestString");
        map.put("test2", "TestVal" + (new Random().nextFloat() * 1000));
        map.put("test3", new int[]{34,3245,534543,2233});
        map.put("test4", new ArrayList<>(Arrays.asList("TestValue1", "TestValue2", "TestValue3")));
    }
    
    @Override
    public String toString() {
        return map.toString();
    }
}

Which serializes to:

         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 00 00 00 d8 05 73 72 01 00 00 00 03 78 70 73 72 |.....sr.....xpsr|
|00000010| 01 00 00 00 04 78 70 73 72 01 00 00 00 05 78 70 |.....xpsr.....xp|
|00000020| 3f 40 00 00 00 00 00 0c 77 08 00 00 00 10 00 00 |[email protected].......|
|00000030| 00 04 74 00 05 74 65 73 74 34 73 72 01 00 00 00 |..t..test4sr....|
|00000040| 06 78 70 00 00 00 03 77 04 00 00 00 03 74 00 0a |.xp....w.....t..|
|00000050| 54 65 73 74 56 61 6c 75 65 31 74 00 0a 54 65 73 |TestValue1t..Tes|
|00000060| 74 56 61 6c 75 65 32 74 00 0a 54 65 73 74 56 61 |tValue2t..TestVa|
|00000070| 6c 75 65 33 78 74 00 05 74 65 73 74 32 74 00 0f |lue3xt..test2t..|
|00000080| 54 65 73 74 56 61 6c 39 30 2e 39 31 30 34 39 74 |TestVal90.91049t|
|00000090| 00 05 74 65 73 74 33 75 72 00 00 02 5b 49 4d ba |..test3ur...[IM.|
|000000a0| 60 26 76 ea b2 a5 02 00 00 78 70 00 00 00 04 00 |`&v......xp.....|
|000000b0| 00 00 22 00 00 0c ad 00 08 28 0f 00 00 08 b9 74 |.."......(.....t|
|000000c0| 00 05 74 65 73 74 31 73 72 01 00 00 00 07 78 72 |..test1sr.....xr|
|000000d0| 01 00 00 00 08 78 70 00 00 00 0c 78             |.....xp....x    |
+--------+-------------------------------------------------+----------------+

Dynamic TCP/UDP Messages

Sometimes we may want to reuse a message for both TCP and UDP comms.

public class TestTCPMessage implements NetworkMessage {

    private final NetworkProtocol protocol;

    public TestTCPMessage(NetworkProtocol protocol) {
        this.protocol = protocol;
    }

    private int someValue;

    @Override
    public String getName() {
        return "Test TCP Message";
    }

    @Override
    public NetworkProtocol getProtocol() {
        return protocol;
    }

    public int getSomeValue() {
        return someValue;
    }

    public void setSomeValue(int someValue) {
        this.someValue = someValue;
    }
}

Clone this wiki locally