Added basic server event objects

Added very simple rendering of character "Tirant" position in another client
This commit is contained in:
Collin Smith
2019-02-05 02:14:18 -08:00
parent 22aaaa9536
commit e23532266f
11 changed files with 309 additions and 21 deletions

View File

@ -318,6 +318,11 @@ public class Entity {
return origin;
}
// TODO: Delete
public void setOrigin(GridPoint2 origin) {
this.origin = origin;
}
public void move() {
if (!mode.equalsIgnoreCase("WL")
&& !mode.equalsIgnoreCase("RN")

View File

@ -22,7 +22,16 @@ import gdx.diablo.codec.excel.Weapons;
import gdx.diablo.item.BodyLoc;
import gdx.diablo.item.Item;
public class Player extends Entity {
public class Player extends Entity implements Cloneable {
@Override
public Player clone() {
try {
return (Player) super.clone();
} catch (CloneNotSupportedException t) {
throw new GdxRuntimeException(t);
}
}
private static final String TAG = "Player";
private static final boolean DEBUG = true;
private static final boolean DEBUG_WCLASS = DEBUG && !true;
@ -61,7 +70,7 @@ public class Player extends Entity {
public Player(String name, CharClass clazz) {
super(null);
super(Diablo.files.PlrType.get(clazz.id).Token, EntType.CHARS);
throw new UnsupportedOperationException();
}

View File

@ -22,6 +22,7 @@ import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.scenes.scene2d.utils.UIUtils;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.Timer;
import org.apache.commons.io.IOUtils;
@ -47,6 +48,12 @@ import gdx.diablo.panel.EscapePanel;
import gdx.diablo.panel.InventoryPanel;
import gdx.diablo.panel.MobilePanel;
import gdx.diablo.panel.StashPanel;
import gdx.diablo.server.Connect;
import gdx.diablo.server.Disconnect;
import gdx.diablo.server.Message;
import gdx.diablo.server.MoveTo;
import gdx.diablo.server.Packet;
import gdx.diablo.server.Packets;
import gdx.diablo.server.PipedSocket;
import gdx.diablo.widget.TextArea;
@ -85,6 +92,7 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable
//Char character;
public Player player;
ObjectMap<String, Player> otherPlayers = new ObjectMap<>();
Timer.Task updateTask;
Socket socket;
@ -228,7 +236,8 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable
String text = input.getText();
if (!text.isEmpty()) {
Gdx.app.debug(TAG, text);
out.println(text);
Message message = new Message(player.stats.getName(), text);
out.println(Packets.build(message));
input.setText("");
}
}
@ -301,8 +310,33 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable
public void render(float delta) {
try {
for (String str; in.ready() && (str = in.readLine()) != null;) {
output.appendText(str);
output.appendText("\n");
Packet packet = Packets.parse(str);
switch (packet.type) {
case Packets.MESSAGE:
Message message = packet.readValue(Message.class);
output.appendText(message.toString());
output.appendText("\n");
break;
case Packets.CONNECT:
Connect connect = packet.readValue(Connect.class);
output.appendText(Diablo.string.format(3641, connect.name));
output.appendText("\n");
Player q = player.clone();
q.setOrigin(player.origin().cpy());
otherPlayers.put(connect.name, q);
break;
case Packets.DISCONNECT:
Disconnect disconnect = packet.readValue(Disconnect.class);
output.appendText(Diablo.string.format(3642, disconnect.name));
output.appendText("\n");
otherPlayers.remove(disconnect.name);
break;
case Packets.MOVETO:
MoveTo moveTo = packet.readValue(MoveTo.class);
Player p = otherPlayers.get(moveTo.name);
if (p != null) p.origin().set(moveTo.x, moveTo.y);
break;
}
}
} catch (IOException e) {
Gdx.app.error(TAG, e.getMessage());
@ -324,6 +358,11 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable
//int spy = - (player.getOrigin().x * Tile.SUBTILE_HEIGHT50) - (player.getOrigin().y * Tile.SUBTILE_HEIGHT50);
//player.draw(b, spx, spy);
player.draw(b);
for (Player p : otherPlayers.values()) {
p.draw(b);
}
b.end();
b.setProjectionMatrix(Diablo.viewport.getCamera().combined);
@ -371,20 +410,22 @@ public class GameScreen extends ScreenAdapter implements LoadingScreen.Loadable
Diablo.input.addProcessor(stage);
Diablo.input.addProcessor(inputProcessorTest);
if (socket != null && socket.isConnected()) {
Gdx.app.log(TAG, "connecting to " + socket.getRemoteAddress() + "...");
in = IOUtils.buffer(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
}
updateTask = Timer.schedule(new Timer.Task() {
@Override
public void run() {
if (UIUtils.shift()) return;
player.move();
mapRenderer.setPosition(player.origin());
String moveTo = Packets.build(new MoveTo(player.stats.getName(), player.origin()));
out.println(moveTo);
}
}, 0, 1 / 25f);
if (socket != null && socket.isConnected()) {
Gdx.app.log(TAG, "connecting to " + socket.getRemoteAddress() + "...");
in = IOUtils.buffer(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
}
}
@Override

View File

@ -0,0 +1,13 @@
package gdx.diablo.server;
public class Connect {
public String name;
private Connect() {}
public Connect(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,13 @@
package gdx.diablo.server;
public class Disconnect {
public String name;
private Disconnect() {}
public Disconnect(String name) {
this.name = name;
}
}

View File

@ -2,9 +2,18 @@ package gdx.diablo.server;
public class Message {
public String from;
public String name;
public String text;
private Message() {}
public Message(String name, String text) {
this.name = name;
this.text = text;
}
@Override
public String toString() {
return name + ": " + text;
}
}

View File

@ -0,0 +1,19 @@
package gdx.diablo.server;
import com.badlogic.gdx.math.GridPoint2;
public class MoveTo {
public String name;
public int x;
public int y;
private MoveTo() {}
public MoveTo(String name, GridPoint2 origin) {
this.name = name;
x = origin.x;
y = origin.y;
}
}

View File

@ -0,0 +1,28 @@
package gdx.diablo.server;
import com.badlogic.gdx.utils.Json;
import com.badlogic.gdx.utils.JsonValue;
public class Packet {
private static final Json JSON = new Json();
public int type;
public int version;
public JsonValue data;
Packet(int type, int version, JsonValue data) {
this.type = type;
this.version = version;
this.data = data;
}
public <T> T readValue(Class<T> type) {
return JSON.readValue(type, data);
}
@Override
public String toString() {
return JSON.toJson(this);
}
}

View File

@ -0,0 +1,65 @@
package gdx.diablo.server;
import com.badlogic.gdx.utils.Json;
import com.badlogic.gdx.utils.JsonReader;
import com.badlogic.gdx.utils.JsonValue;
import com.badlogic.gdx.utils.ObjectIntMap;
public class Packets {
private static final Json JSON = new Json();
private Packets() {}
public static final int MESSAGE = 1;
public static final int CONNECT = 2;
public static final int DISCONNECT = 3;
public static final int MOVETO = 4;
private static final ObjectIntMap<Class> MAP;
static {
MAP = new ObjectIntMap<>();
MAP.put(Message.class, 1);
MAP.put(Connect.class, 2);
MAP.put(Disconnect.class, 3);
MAP.put(MoveTo.class, 4);
}
public static <T> T parse(Class<T> type, String json) {
return parse(json).readValue(type);
}
public static Packet parse(String json) {
// TODO: Replace with indexes when well-formed later on
JsonValue value = new JsonReader().parse(json);
int type = value.getInt("type", 0);
int version = value.getInt("version", 0);
JsonValue data = value.get("data");
return new Packet(type, version, data);
}
public static int getType(String json) {
return new JsonReader().parse(json).getInt("type", 0);
}
public static String build(Object instance) {
int type = MAP.get(instance.getClass(), 0);
if (type == 0) return null;
//JsonValue data = new JsonReader().parse(JSON.toJson(instance));
EncodedJsonPacket obj = new EncodedJsonPacket(type, 0, instance);
return JSON.toJson(obj);
}
private static class EncodedJsonPacket {
int type;
int version;
Object data;
EncodedJsonPacket() {}
EncodedJsonPacket(int type, int version, Object data) {
this.type = type;
this.version = version;
this.data = data;
}
}
}

View File

@ -7,6 +7,7 @@ import com.badlogic.gdx.net.ServerSocket;
import com.badlogic.gdx.net.Socket;
import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.Json;
import com.badlogic.gdx.utils.JsonReader;
import org.apache.commons.io.IOUtils;
@ -51,7 +52,7 @@ public class Server implements Disposable, Runnable {
while (!kill.get()) {
try {
Socket socket = server.accept(null);
new Client(socket).start();
new Client(socket, "Tirant").start();
Gdx.app.log(name, "connection from " + socket.getRemoteAddress());
} catch (Throwable t) {
Gdx.app.log(name, t.getMessage(), t);
@ -122,10 +123,12 @@ public class Server implements Disposable, Runnable {
Socket socket;
BufferedReader in;
PrintWriter out;
String name;
public Client(Socket socket) {
public Client(Socket socket, String name) {
super(clientThreads, "Client-" + String.format("%08X", MathUtils.random(1, Integer.MAX_VALUE - 1)));
this.socket = socket;
this.name = name;
}
@Override
@ -134,33 +137,55 @@ public class Server implements Disposable, Runnable {
in = IOUtils.buffer(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
String connect = Packets.build(new Connect(name));
for (Client client : clients) {
client.out.println("CONNECT " + socket.getRemoteAddress());
client.out.println(connect);
//client.out.println("CONNECT " + socket.getRemoteAddress());
}
clients.add(this);
for (String input; (input = in.readLine()) != null; ) {
for (String input; (input = in.readLine()) != null;) {
//Message message = Packets.parse(Message.class, input);
String message = "MESSAGE " + socket.getRemoteAddress() + ": " + input;
Gdx.app.log(getName(), message);
for (Client client : clients) {
client.out.println(message);
}
}
Packet packet = Packets.parse(input);
switch (packet.type) {
case Packets.MESSAGE:
for (Client client : clients) {
//client.out.println(message);
client.out.println(input);
}
break;
case Packets.MOVETO:
for (Client client : clients) {
if (client == this) continue;
client.out.println(input);
}
break;
}
}
} catch (Throwable t) {
Gdx.app.log(getName(), "ERROR " + socket.getRemoteAddress() + ": " + t.getMessage());
} finally {
clients.remove(this);
String message = "DISCONNECT " + socket.getRemoteAddress();
Gdx.app.log(getName(), message);
String disconnect = Packets.build(new Disconnect(name));
for (Client client : clients) {
client.out.println(message);
client.out.println(disconnect);
}
//IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
if (socket != null) socket.dispose();
}
}
private void tmp() {
JsonReader reader = new JsonReader();
}
}
}

View File

@ -0,0 +1,61 @@
package gdx.diablo.server;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.headless.HeadlessApplication;
import com.badlogic.gdx.utils.Json;
import org.junit.Assert;
import org.junit.Test;
import gdx.diablo.Diablo;
import gdx.diablo.codec.StringTBLs;
import gdx.diablo.mpq.MPQFileHandleResolver;
public class PacketsTest {
@Test
public void getType() {
int type = Packets.getType("{ \"type\": 1, \"version\": 1, \"data\": { \"name\": \"Tirant\", \"text\": \"Hello World!\" } }");
Assert.assertEquals(Packets.MESSAGE, type);
}
@Test
public void parsePacketType() {
Packet packet = Packets.parse("{ \"type\": 1, \"version\": 1, \"data\": { \"name\": \"Tirant\", \"text\": \"Hello World!\" } }");
Assert.assertEquals(Packets.MESSAGE, packet.type);
}
@Test
public void parsePacketVersion() {
Packet packet = Packets.parse("{ \"type\": 1, \"version\": 1, \"data\": { \"name\": \"Tirant\", \"text\": \"Hello World!\" } }");
Assert.assertEquals(1, packet.version);
}
@Test
public void parsePacketData() {
Packet packet = Packets.parse("{ \"type\": 1, \"version\": 1, \"data\": { \"name\": \"Tirant\", \"text\": \"Hello World!\" } }");
Message message = new Json().readValue(Message.class, packet.data);
System.out.println("message " + message);
}
@Test
public void parsePacketData_Event() {
new HeadlessApplication(new ApplicationAdapter() {}, null);
MPQFileHandleResolver resolver = new MPQFileHandleResolver();
resolver.add(Gdx.files.absolute("C:\\Program Files (x86)\\Steam\\steamapps\\common\\Diablo II\\patch_d2.mpq"));
resolver.add(Gdx.files.absolute("C:\\Program Files (x86)\\Steam\\steamapps\\common\\Diablo II\\d2exp.mpq"));
resolver.add(Gdx.files.absolute("C:\\Program Files (x86)\\Steam\\steamapps\\common\\Diablo II\\d2data.mpq"));
Diablo.string = new StringTBLs(resolver);
Packet packet = Packets.parse("{ \"type\": 2, \"version\": 1, \"data\": { \"id\": 3643, \"args\": [ \"Tirant\", \"email\" ] } }");
Event event = packet.readValue(Event.class);
System.out.println("event " + event);
Gdx.app.exit();
}
@Test
public void buildPacket() {
Message message = new Message("Tirant", "Hello World!");
System.out.println("msg:" + Packets.build(message));
}
}