Skip to content

Client Server

Vrekt edited this page Apr 8, 2024 · 10 revisions

Local client server

The client server is how the local client communicates with the remote server.

Protocol

First, we need to define our protocol. In this example we will just provide these values in our function, but you may choose to keep a global class that holds the current protocol version and name.

final int protocolVersion = 1;
final String protocolName = "GameProtocol";
// true if default packets should be initialized
final GdxProtocol protocol = new GdxProtocol(protocolVersion, protocolName, true);

Now that we have that we can move onto creating our client server instance.

final LunarClientServer cs = new LunarClientServer(protocol, "localhost", 4290);
// provide the connection provider.
// this describes the handler to use for incoming packets
cs.setConnectionProvider(channel -> new PlayerConnection(channel, protocol, myPlayer));

// now, try to connect to remote server
try {
   clientServer.connect();
} catch (Exception exception) {
   GameLogging.exceptionThrown(GAME_VERSION, "Exception thrown during connection stage", exception);
   Gdx.app.exit();
}

// lets ensure the connection was created successfully
if(cs.getConnection() == null throw new RuntimeException("Failed to create connection"));

// finally, lets get our PlayerConnection instance
final PlayerConnection handler = cs.getConnection();
myPlayer.setUseConnection(handler); // for example

Now the client is connected to the remote server. What you do after is up to you, for example you may request to join a world.

handler.joinWorld("SomeServerWorld", myPlayer.getName())

Connection configuration

By default, all connection options are handled with Lunar. You can change this behaviour and pick and choose which packets you want to provide custom implementation for (or all of them!)

If you wish to use your own connection handler you can simply extend PlayerConnectionHandler

public final class MyPlayerConnection extends PlayerConnectionHandler {}

Make sure you register the client server to use this handler

cs.setConnectionProvider(channel -> new MyPlayerConnection(channel, protocol, myPlayer));

With this, you could handle your own custom packets.

public MyPlayerConnection(Channel channel, GdxProtocol protocol, OasisPlayer player) {
    super(channel, protocol);
    this.player = player;

    registerPacket(MyCustomPacket1.ID, MyCustomPacket1::new, this::handleCustomPacket1);
    registerPacket(MyCustomPacket2.ID, MyCustomPacket2::new, this::handleCustomPacket2);
    registerPacket(MyCustomPacket3.ID, MyCustomPacket3::new, this::handleCustomPacket3);
}

You could also override default behaviour.

@Override
public void handleAuthentication(ServerPacketAuthenticate packet) {
    doAdvancedAuthenticationOn(packet);
}

Another option of overriding default behaviour is simply registering a handler within your connection.

myPlayerConnection.registerHandlerSync(SomePacket.ID, packet -> doSomethingElse((SomePacket) packet));

In my game, I override the ping handling so I can update my GUI elements.

connectionHandler.registerHandlerSync(ServerPacketPing.PACKET_ID, packet -> updatePingTime((ServerPacketPing) packet));

// later
private void updatePingTime(ServerPacketPing packet) {
    final long now = System.currentTimeMillis();
    serverPingTime = now - packet.getClientTime();
}