Added basic server support (create/join games and chat)

Separated services into ChatServer, DedicatedServer and Sessions
Single player uses same code-base as DedicatedServer with a special loopback socket
Added SelectCharacterScreen2 copy -- will replace later on with more versatile SelectCharacterScreen impl
This commit is contained in:
Collin Smith
2019-02-03 02:47:08 -08:00
parent a1e735031f
commit 49f1058566
16 changed files with 719 additions and 80 deletions

View File

@ -94,7 +94,7 @@ public class ChatServer extends ApplicationAdapter {
PrintWriter out;
public Client(Socket socket) {
super(clientThreads, "Client-" + String.format("%08X", MathUtils.random(1, Integer.MAX_VALUE)));
super(clientThreads, "Client-" + String.format("%08X", MathUtils.random(1, Integer.MAX_VALUE - 1)));
this.socket = socket;
}
@ -103,6 +103,14 @@ public class ChatServer extends ApplicationAdapter {
try {
in = IOUtils.buffer(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
final Calendar calendar = Calendar.getInstance();
DateFormat format = DateFormat.getDateTimeInstance();
out.println("BNET " + format.format(calendar.getTime()));
for (PrintWriter client : clients) {
client.println("CONNECT " + socket.getRemoteAddress());
}
clients.add(out);
for (String input; (input = in.readLine()) != null; ) {

View File

@ -0,0 +1,43 @@
package gdx.diablo.server;
import com.badlogic.gdx.utils.Disposable;
import java.util.concurrent.atomic.AtomicBoolean;
public class DedicatedServer extends Thread implements Disposable {
private static final String TAG = "DedicatedServer";
Server server;
AtomicBoolean kill;
DedicatedServer(ThreadGroup group, String name, Server target) {
super(group, target, name);
server = target;
kill = new AtomicBoolean(false);
}
public static DedicatedServer newDedicatedServer(ThreadGroup group, String name, int port) {
Server server = new Server(port, name);
return new DedicatedServer(group, name, server);
}
@Override
public void run() {
super.run();
while (!kill.get()) {
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {}
server.update();
}
}
@Override
public void dispose() {
kill.set(true);
//try {
// join();
//} catch (InterruptedException ignored) {}
server.dispose();
}
}

View File

@ -1,39 +0,0 @@
package gdx.diablo.server;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Net;
import com.badlogic.gdx.net.ServerSocket;
import com.badlogic.gdx.net.Socket;
import com.badlogic.gdx.utils.Json;
import java.util.concurrent.atomic.AtomicBoolean;
public class Server extends Thread {
private static final String TAG = "Server";
private final Json json = new Json();
ServerSocket server;
AtomicBoolean kill;
int port;
Server(ThreadGroup group, String name, int port) {
super(group, name);
this.port = port;
kill = new AtomicBoolean(false);
}
@Override
public void run() {
server = Gdx.net.newServerSocket(Net.Protocol.TCP, port, null);
while (!kill.get()) {
Socket client = null;
try {
client = server.accept(null);
Gdx.app.log(getName(), "connection from " + client.getRemoteAddress());
} finally {
if (client != null) client.dispose();
}
}
}
}

View File

@ -147,8 +147,8 @@ public class ServerBrowser extends ApplicationAdapter {
session.port = 6114 + sessions.size();
sessions.put(session.getName(), session);
String id = String.format("%08x", MathUtils.random(Integer.MAX_VALUE - 1));
Server server = new Server(sessionGroup, "Session-" + id, session.port);
String id = String.format("%08X", MathUtils.random(1, Integer.MAX_VALUE - 1));
DedicatedServer server = DedicatedServer.newDedicatedServer(sessionGroup, "Session-" + id, session.port);
server.start();
servers.put(session.getName(), server);

View File

@ -5,12 +5,16 @@ import com.badlogic.gdx.Net;
import com.badlogic.gdx.backends.headless.HeadlessApplication;
import com.badlogic.gdx.backends.headless.HeadlessApplicationConfiguration;
import com.badlogic.gdx.net.HttpRequestBuilder;
import com.badlogic.gdx.net.Socket;
import com.badlogic.gdx.utils.Json;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicBoolean;
public class ServerTest {
@ -19,7 +23,7 @@ public class ServerTest {
@Before
public void setUp() throws Exception {
HeadlessApplicationConfiguration config = new HeadlessApplicationConfiguration();
new HeadlessApplication(new Server(), config);
new HeadlessApplication(new ServerBrowser(), config);
}
@After
@ -122,4 +126,103 @@ public class ServerTest {
});
while (!done.get()) ;
}
@Test
public void testConnect() {
final AtomicBoolean done = new AtomicBoolean();
Net.HttpRequest request = new HttpRequestBuilder()
.newRequest()
.method(Net.HttpMethods.POST)
.url("http://hydra:6112/create-session")
.jsonContent(new Session.Builder() {{
name = "test game";
password = "1111";
desc = "test desc";
}})
.build();
Gdx.net.sendHttpRequest(request, new Net.HttpResponseListener() {
@Override
public void handleHttpResponse(Net.HttpResponse httpResponse) {
Session session = new Json().fromJson(Session.class, httpResponse.getResultAsString());
Gdx.app.log(TAG, httpResponse.getResultAsString());
Socket socket = null;
try {
socket = Gdx.net.newClientSocket(Net.Protocol.TCP, session.host, session.port, null);
} finally {
if (socket != null) socket.dispose();
}
done.set(true);
}
@Override
public void failed(Throwable t) {
Gdx.app.log(TAG, ObjectUtils.toString(t));
done.set(true);
}
@Override
public void cancelled() {
Gdx.app.log(TAG, "cancelled");
done.set(true);
}
});
while (!done.get());
}
@Test
public void testDisconnect() {
final AtomicBoolean done = new AtomicBoolean();
Net.HttpRequest request = new HttpRequestBuilder()
.newRequest()
.method(Net.HttpMethods.POST)
.url("http://hydra:6112/create-session")
.jsonContent(new Session.Builder() {{
name = "test game";
password = "1111";
desc = "test desc";
}})
.build();
Gdx.net.sendHttpRequest(request, new Net.HttpResponseListener() {
@Override
public void handleHttpResponse(Net.HttpResponse httpResponse) {
Session session = new Json().fromJson(Session.class, httpResponse.getResultAsString());
Socket socket = null;
try {
socket = Gdx.net.newClientSocket(Net.Protocol.TCP, session.host, session.port, null);
Gdx.app.log(TAG, "Connected: " + socket.isConnected());
new PrintWriter(socket.getOutputStream(), true).println("test");
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {}
} finally {
Gdx.app.log(TAG, "disconnecting...");
if (socket != null) {
//IOUtils.closeQuietly(socket.getInputStream());
IOUtils.closeQuietly(socket.getOutputStream());
socket.dispose();
}
}
try {
Thread.sleep(500);
} catch (InterruptedException ignored) {}
done.set(true);
}
@Override
public void failed(Throwable t) {
Gdx.app.log(TAG, ObjectUtils.toString(t));
done.set(true);
}
@Override
public void cancelled() {
Gdx.app.log(TAG, "cancelled");
done.set(true);
}
});
while (!done.get()) ;
}
}