The Async-mmocore is primarily designed to Massive Multiplayer Online (MMO) Game Servers. The Goal of the Async-mmocore is to provide an easy way to handle MMO connections to a server abstracting the networking layer complexity.
The Async-mmocore is built on top of Java NIO.2 API using Asynchronous Socket Channels. It is recommended Java 11+ to build and run.
These classes, herein referenced as packets, are the abstraction of data send through the network. All packets must have a Header and an optional payload.
The header is a Short number the carries out the size the packet. The payload is the essential information to the server or client. The packet must be composed by at maximum 32767 bytes. Packets greater than this can be lead to unexpected behaviour.
The client Class is a representation of an external connection. Thus, it's the unique source of incoming packets and the target of the outcome packets.
The Client Class must implement the abstract class Client
public class ClientImpl extends Client<Connection<ClientImpl>> {
public ClientImpl(Connection<ClientImpl> connection) {
super(connection);
}
@Override
public boolean decrypt(Buffer data, int offset, int size) {
return myCrypter.decrypt(data, offset, size);
}
@Override
public boolean encrypt(Buffer data, int offset, int size) {
return myCrypter.encrypt(data, offset, size);
}
@Override
protected void onDisconnection() {
saveDataAndReleaseResources();
}
@Override
public void onConnected() {
doTheInitialJob();
}
public void sendPacket(WritablePacket<ClientImpl> packet) {
writePacket(packet);
}
}
The Client Factory instantiate the new incoming connections.
The Client Factory must implement the interface ClientFactory
public class ClientFactoryImpl implements ClientFactory<ClientImpl> {
@Override
public ClientImpl create(Connection<ClientImpl> connection) {
return new ClientImpl(connection);
}
}
The Packet Handler converts the incoming data into a ReadablePacket.
The Packet Handler must implement the interface PacketHandler
public class PacketHandlerImpl implements PacketHandler<ClientImpl> {
@Override
public ReadablePacket<ClientImpl> handlePacket(ReadableBuffer buffer, ClientImpl client) {
ReadablePacket<ClientImpl> packet = convertToPacket(buffer, client);
return packet;
}
}
The Packet Executor executes the incoming Packets.
Although the packet can be executed in the same Thread, it's HIGHLY recommended that the Executors executes the packet on an apart Thread. That's because the Thread that calls the execute method is the same which process the network I/O operations. Thus, these threads must be short-living and execute only non-blocking operations.
The Packet Executor must implement the interface PacketExecutor
public class PacketExecutorImpl implements PacketExecutor<ClientImpl> {
@Override
public void execute(ReadablePacket<AsyncClient> packet) {
threadPoolExecutor.execute(packet);
}
}
To listen Connections it's necessary to build a ConnectionHandler
public class ServerHandler {
public void startListen(String host, int port) {
ConnectionHandler<ClientImpl> connectionHandler = ConnectionBuilder.create(new InetSocketAddress(host, port), new ClientFactoryImpl(), new PacketHandlerImpl(), new PacketExecutorImpl()).build();
connectionHandler.start();
}
}
To send a Packet it's necessary to implement the abstract class WritablePacket
public class ServerInfo implements WritablePacket<ClientImpl> {
@Override
protected boolean write(ClientImpl client, WritableBuffer buffer) {
buffer.writeByte(this.getServerId());
buffer.writeString(this.getServerName());
buffer.writeLong(this.getServerCurrentTime());
buffer.writeInt(this.getServerCurrentUsers());
return true;
}
}
After it just send it through the client
public class ServerHandler {
public void sendServerInfoToClient(ClientImpl client) {
client.sendPacket(new ServerInfo());
}
}
The receiving packet is almost all done by the Async-mmocore. The only part to be implemented to fully read is the steps described in Define a Packet Handler Implementation and Define a Packet Executor Implementation sections.
public class ReceivedServerInfo implements ReadablePacket<ClientImpl> {
@Override
protected boolean read() {
this.serverId = readByte();
this.serverName = readString();
this.serverCurrentTime = readLong();
this.serverCurrentUsers = readInt();
return true;
}
@Override
public void run() {
showServerInfoToClient();
}
}
The class Connector provides client side asynchronous connection support. It works just like ConnectionBuilder, so you must define the ClientFactory, the PacketHandler and the PacketExecutor implementations.
public class ConnectionFactory {
public static ClientImpl create(String host, int port) {
ClientImpl client = Connector.create(clientFactory, packetHandler, packetExecutor).connect(new InetSocketAddress(host, port));
return client;
}
}