better map messaging

main
Brett 2023-04-20 17:30:51 -04:00
parent c106cca6b1
commit 941aa58576
5 changed files with 87 additions and 23 deletions

View File

@ -6,7 +6,7 @@ import java.io.*;
public class Main { public class Main {
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
Client gameClient = new Client("localhost"); new Client("localhost");
} }
} }

View File

@ -53,7 +53,7 @@ public class GameDisplay {
Integer.toString(map.getTownHall().getGoldCapacity()), Integer.toString(map.getTownHall().getGoldCapacity()),
Integer.toString(map.getTownHall().getCurrentGold()))); Integer.toString(map.getTownHall().getCurrentGold())));
Print.print(resourcesPrinter.createTable(true, false, true)); ArrayList<String> total = new ArrayList<>(resourcesPrinter.createTable(true, false, true));
Print buildingPrinter = new Print("Village Buildings", 2, resourcesPrinter.getWidth()); Print buildingPrinter = new Print("Village Buildings", 2, resourcesPrinter.getWidth());
buildingPrinter.addColumn(new Print.Column("Name")); buildingPrinter.addColumn(new Print.Column("Name"));
@ -65,7 +65,7 @@ public class GameDisplay {
Integer.toString(b.getLevel() + 1), Integer.toString(b.getLevel() + 1),
Integer.toString(b.getHealth()))); Integer.toString(b.getHealth())));
Print.print(buildingPrinter.createTable(true, false, true)); total.addAll(buildingPrinter.createTable(true, false, true));
Print inhabs = new Print("Village Inhabitants", 2, buildingPrinter.getWidth()); Print inhabs = new Print("Village Inhabitants", 2, buildingPrinter.getWidth());
inhabs.addColumn(new Print.Column("Name")); inhabs.addColumn(new Print.Column("Name"));
@ -74,7 +74,11 @@ public class GameDisplay {
for (Inhabitant i : map.inhabitants) for (Inhabitant i : map.inhabitants)
inhabs.addRow(new Print.Row(i.getClass().getSimpleName(), Integer.toString(i.getLevel() + 1))); inhabs.addRow(new Print.Row(i.getClass().getSimpleName(), Integer.toString(i.getLevel() + 1)));
return inhabs.createTable(true, true, true); total.addAll(inhabs.createTable(true, true, true));
System.out.println(buildingPrinter.getWidth());
System.out.println(resourcesPrinter.getWidth());
System.out.println(inhabs.getWidth());
return total;
} }
public void printVillageState(Map map, String displayName) { public void printVillageState(Map map, String displayName) {

View File

@ -22,6 +22,9 @@ public class Client implements Runnable {
private final Map<Long, Message.Sent> sentMessages = Collections.synchronizedMap(new HashMap<>()); private final Map<Long, Message.Sent> sentMessages = Collections.synchronizedMap(new HashMap<>());
private int lastMessageID = 0; private int lastMessageID = 0;
private final InetAddress serverAddress; private final InetAddress serverAddress;
private String[] lineBuffer = new String[0];
private int expectedLines = 0;
private int currentLines = 0;
private long ourClientID = 0; private long ourClientID = 0;
@ -120,7 +123,23 @@ public class Client implements Runnable {
case PacketTable.MESSAGE: case PacketTable.MESSAGE:
System.out.println(stream.readUTF()); System.out.println(stream.readUTF());
break; break;
case PacketTable.BEGIN_MAP_DATA:
expectedLines = stream.readInt();
currentLines = 0;
lineBuffer = new String[expectedLines];
break;
case PacketTable.MAP_LINE_DATA:
int lineNumber = stream.readInt();
lineBuffer[lineNumber] = stream.readUTF();
currentLines++;
if (currentLines >= expectedLines) {
for (String line : lineBuffer){
System.out.println(line);
}
}
break;
case PacketTable.DISCONNECT: case PacketTable.DISCONNECT:
System.out.println("Disconnecting!");
running = false; running = false;
break; break;
} }

View File

@ -22,7 +22,10 @@ public class PacketTable {
public static final byte TRAIN = 0x6; public static final byte TRAIN = 0x6;
// messageHeader, upgrade // messageHeader, upgrade
public static final byte UPGRADE = 0x7; public static final byte UPGRADE = 0x7;
// messageHeader, serial packets with map info // messageHeader
public static final byte PRINT_MAP_DATA = 0x8; public static final byte PRINT_MAP_DATA = 0x8; // client -> server only!
// messageHeader, line count
public static final byte BEGIN_MAP_DATA = 0x9; // server -> client
// messageHeader, line number (int), UTF8 String (the line)
public static final byte MAP_LINE_DATA = 0xA; // server -> client
} }

View File

@ -143,6 +143,9 @@ public class Server implements Runnable {
throw new RuntimeException("A message was acknowledged but does not exist!"); throw new RuntimeException("A message was acknowledged but does not exist!");
message.acknowledged(); message.acknowledged();
sentMessages.remove(request.getMessageID()); sentMessages.remove(request.getMessageID());
synchronized (sentMessages) {
sentMessages.notifyAll();
}
break; break;
case PacketTable.MESSAGE: case PacketTable.MESSAGE:
System.out.println(request.getReader().readUTF()); System.out.println(request.getReader().readUTF());
@ -165,7 +168,7 @@ public class Server implements Runnable {
usingEngine.upgradeBuilding(clientMap, Integer.parseInt(request.getReader().readUTF())); usingEngine.upgradeBuilding(clientMap, Integer.parseInt(request.getReader().readUTF()));
break; break;
case PacketTable.PRINT_MAP_DATA: case PacketTable.PRINT_MAP_DATA:
usingEngine.view.getVillageStateTable(clientMap, "Home Village").forEach(this::sendMessageLn); sendMapData(usingEngine.view.getVillageStateTable(clientMap, "Home Village"));
break; break;
} }
if (request.getPacketID() != PacketTable.ACK) if (request.getPacketID() != PacketTable.ACK)
@ -187,35 +190,70 @@ public class Server implements Runnable {
} }
requestLock.unlock(); requestLock.unlock();
ArrayList<Long> removes = new ArrayList<>(); // sentEntries needn't be in the synchronized block
for (HashMap.Entry<Long, Message.Sent> message : sentMessages.entrySet()){ Set<HashMap.Entry<Long, Message.Sent>> sentEntries = sentMessages.entrySet();
Message.Sent sent = message.getValue(); synchronized (sentMessages) {
if (!sent.isAcknowledged() && sent.getTimeSinceSent().get() > MAX_PACKET_ACK_TIME_SECONDS) { ArrayList<Long> removes = new ArrayList<>();
System.out.println("The client did not acknowledge our message, did they receive it?"); for (HashMap.Entry<Long, Message.Sent> message : sentEntries) {
sendMessage(sent); Message.Sent sent = message.getValue();
removes.add(message.getKey()); if (!sent.isAcknowledged() && sent.getTimeSinceSent().get() > MAX_PACKET_ACK_TIME_SECONDS) {
System.out.println("The client did not acknowledge our message, did they receive it?");
sendMessage(sent);
removes.add(message.getKey());
}
} }
for (Long l : removes)
sentMessages.remove(l);
} }
for (Long l : removes)
sentMessages.remove(l);
} }
} }
private void sendMessageLn(String str) { private void sendMapData(ArrayList<String> lines) {
final long messageID = ++lastSentMessageID;
Message.Sent beginMapInfoMessage = new Message.Sent(PacketTable.BEGIN_MAP_DATA, clientID, messageID);
try {
beginMapInfoMessage.getWriter().writeInt(lines.size());
sendMessage(beginMapInfoMessage);
} catch (IOException e) {
sendAndLogLn("Unable to send map data: " + e.getMessage());
return;
}
new Thread(() -> {
while (sentMessages.containsKey(messageID)){
try {
synchronized (sentMessages) {
sentMessages.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// once we know that the client is waiting on our map data, we can send it in any order.
for (int i = 0; i < lines.size(); i++){
Message.Sent line = new Message.Sent(PacketTable.MAP_LINE_DATA, clientID, ++lastSentMessageID);
try {
// but we need the line index!
line.getWriter().writeInt(i);
line.getWriter().writeUTF(lines.get(i));
} catch (IOException e){
e.printStackTrace();
}
sendMessage(line);
}
}).start();
}
private void sendAndLogLn(String str){
Message.Sent mess = new Message.Sent(PacketTable.MESSAGE, clientID, ++lastSentMessageID); Message.Sent mess = new Message.Sent(PacketTable.MESSAGE, clientID, ++lastSentMessageID);
try { try {
mess.getWriter().writeUTF(str + "\n"); mess.getWriter().writeUTF(str + "\n");
sendMessage(mess); sendMessage(mess);
System.out.println(str);
} catch (IOException e){ } catch (IOException e){
e.printStackTrace(); e.printStackTrace();
} }
} }
private void sendAndLogLn(String str){
sendMessageLn(str);
System.out.println(str);
}
public void sendMessage(Message.Sent message){ public void sendMessage(Message.Sent message){
if (message.getPacketID() != PacketTable.ACK) if (message.getPacketID() != PacketTable.ACK)