package com.github.czyzby; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.actions.Actions; import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.utils.viewport.FitViewport; import com.github.czyzby.kiwi.util.common.Strings; import com.github.czyzby.kiwi.util.gdx.AbstractApplicationListener; import com.github.czyzby.kiwi.util.gdx.asset.Disposables; import com.github.czyzby.lml.annotation.LmlAction; import com.github.czyzby.lml.annotation.LmlActor; import com.github.czyzby.lml.parser.LmlView; import com.github.czyzby.lml.parser.action.ActionContainer; import com.github.czyzby.lml.vis.util.VisLml; import com.github.czyzby.shared.MyPackets; import com.github.czyzby.shared.Ping; import com.github.czyzby.shared.Pong; import com.github.czyzby.websocket.WebSocket; import com.github.czyzby.websocket.WebSocketHandler; import com.github.czyzby.websocket.WebSocketHandler.Handler; import com.github.czyzby.websocket.WebSocketListener; import com.github.czyzby.websocket.WebSockets; import com.github.czyzby.websocket.net.ExtendedNet; import com.github.czyzby.websocket.serialization.impl.ManualSerializer; import com.kotcrab.vis.ui.VisUI; import com.kotcrab.vis.ui.widget.VisTextField; // LmlView and ActionContainer are interfaces used to for UI library: gdx-lml-vis. // AbstractApplicationListener is an alternative to ApplicationAdapter from gdx-kiwi. public class Core extends AbstractApplicationListener implements LmlView, ActionContainer { /** Preferred window size. Virtual size of viewport. */ public static final int WIDTH = 480, HEIGHT = 340; private Stage stage; private WebSocket socket; // Injected by gdx-lml-vis parser during processing of core.lml: @LmlActor("status") Label statusLabel; @LmlActor("input") VisTextField inputField; @Override public void create() { // Note: you can also use WebSockets.newSocket() and WebSocket.toWebSocketUrl() methods. socket = ExtendedNet.getNet().newWebSocket("localhost", 8000); socket.addListener(getListener()); // Creating a new ManualSerializer - this replaces the default JsonSerializer and allows to use the // serialization mechanism from gdx-websocket-serialization library. final ManualSerializer serializer = new ManualSerializer(); socket.setSerializer(serializer); // Registering all expected packets: MyPackets.register(serializer); // Creating UI with gdx-lml-vis: stage = new Stage(new FitViewport(WIDTH, HEIGHT)); Gdx.input.setInputProcessor(stage); VisUI.load(); VisLml.parser().build().createView(this, Gdx.files.internal("core.lml")); // Smooth screen fading in: stage.addAction(Actions.sequence(Actions.alpha(0f), Actions.alpha(1f, 1f))); // Connecting with the server. socket.connect(); } private WebSocketListener getListener() { // WebSocketHandler is an implementation of WebSocketListener that uses the current Serializer (ManualSerializer // in this case) to create objects from received raw data. Instead of forcing you to work with Object and do // manual casting, this listener allows to register handlers for each expected packet class. final WebSocketHandler handler = new WebSocketHandler(); // Registering Ping handler: handler.registerHandler(Ping.class, new Handler<Ping>() { @Override public boolean handle(final WebSocket webSocket, final Ping packet) { statusLabel.setText("Received PING: " + packet.getValue() + "!"); return true; } }); // Registering Pong handler: handler.registerHandler(Pong.class, new Handler<Pong>() { @Override public boolean handle(final WebSocket webSocket, final Pong packet) { statusLabel.setText("Received PONG: " + packet.getValue() + "!"); return true; } }); // Side note: this would be a LOT cleaner with Java 8 lambdas (or using another JVM language, like Kotlin). return handler; } // Invoked by buttons in core.lml template: @LmlAction("sendPing") public void sendPingPacket() { final Ping ping = new Ping(); ping.setValue(getInput()); ping.setClient(true); socket.send(ping); } @LmlAction("sendPong") public void sendPongPacket() { final Pong pong = new Pong(); pong.setValue(getInput()); pong.setServer(false); socket.send(pong); } private int getInput() { if (inputField.isEmpty()) { return 0; } final int input = Integer.parseInt(inputField.getText()); inputField.setText(Strings.EMPTY_STRING); return input; } @Override public void resize(final int width, final int height) { stage.getViewport().update(width, height); } @Override protected void render(final float deltaTime) { stage.act(deltaTime); stage.draw(); } @Override public void dispose() { WebSockets.closeGracefully(socket); // Null-safe closing method that catches and logs any exceptions. Disposables.disposeOf(stage); VisUI.dispose(); } // LmlView methods, used to parse core.lml template: @Override public Stage getStage() { return stage; } @Override public String getViewId() { return "core"; } }