Compare commits
No commits in common. "ce814df02ea2683e2e4f5daf0b0c05bb8e2f3074" and "fc0981852a6e232a9aa0e3f31b60620b0291c240" have entirely different histories.
ce814df02e
...
fc0981852a
Binary file not shown.
|
@ -3,10 +3,10 @@ package ca.cosc3p91.a4;
|
||||||
import ca.cosc3p91.a4.util.network.Client;
|
import ca.cosc3p91.a4.util.network.Client;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
public class MainClient {
|
public class Main {
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
new Client("localhost");
|
Client gameClient = new Client("localhost");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
package ca.cosc3p91.a4;
|
|
||||||
|
|
||||||
import ca.cosc3p91.a4.util.network.Server;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class MainServer {
|
|
||||||
public static void main(String[] args) throws IOException, InterruptedException {
|
|
||||||
new Server();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,6 @@ import ca.cosc3p91.a4.gameobjects.factory.InhabitantFactory;
|
||||||
import ca.cosc3p91.a4.player.*;
|
import ca.cosc3p91.a4.player.*;
|
||||||
import ca.cosc3p91.a4.userinterface.GameDisplay;
|
import ca.cosc3p91.a4.userinterface.GameDisplay;
|
||||||
import ca.cosc3p91.a4.util.ChallengeAdapter;
|
import ca.cosc3p91.a4.util.ChallengeAdapter;
|
||||||
import ca.cosc3p91.a4.util.network.Server;
|
|
||||||
|
|
||||||
import java.beans.XMLEncoder;
|
import java.beans.XMLEncoder;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
|
@ -20,31 +19,36 @@ public class GameEngine {
|
||||||
public static final double IRON_FACTOR = 1;
|
public static final double IRON_FACTOR = 1;
|
||||||
public static final double WOOD_FACTOR = 0.1;
|
public static final double WOOD_FACTOR = 0.1;
|
||||||
|
|
||||||
|
private float pillageFactor = 0.5f;
|
||||||
|
|
||||||
private int currentTime;
|
private int currentTime;
|
||||||
|
|
||||||
private final Random random = new Random(System.nanoTime());
|
private final Random random = new Random(System.nanoTime());
|
||||||
|
|
||||||
public GameDisplay view = new GameDisplay();
|
public GameDisplay view;
|
||||||
|
|
||||||
public GameEngine() {
|
public GameEngine() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean attackVillage(Map attacking, Map defending, boolean simulated, Server.ConnectedClient client) {
|
public void attackVillage(Map attacking, Map defending) {
|
||||||
int defenseiveCounter = 1;
|
// int defenseiveCounter = 1;
|
||||||
int inhabCounter = 0;
|
// int inhabCounter = 0;
|
||||||
for (Building b : defending.contains)
|
// for (Building b : map.contains)
|
||||||
if (b instanceof DefenseBuilding)
|
// if (b instanceof DefenseBuilding)
|
||||||
defenseiveCounter++;
|
// defenseiveCounter++;
|
||||||
for (Inhabitant i : defending.inhabitants)
|
// for (Inhabitant i : map.inhabitants)
|
||||||
if (i instanceof Infantry)
|
// if (i instanceof Infantry)
|
||||||
inhabCounter++;
|
// inhabCounter++;
|
||||||
float pillageFactor = (float) inhabCounter / (float) defenseiveCounter;
|
// pillageFactor = (float) inhabCounter / (float) defenseiveCounter;
|
||||||
if (pillageFactor < 0)
|
// if (pillageFactor < 0)
|
||||||
pillageFactor = 0;
|
// pillageFactor = 0;
|
||||||
if (pillageFactor > 1)
|
// if (pillageFactor > 1)
|
||||||
pillageFactor = 1;
|
// pillageFactor = 1;
|
||||||
|
// this.map.getTownHall().addWood((int) (map.getTownHall().getCurrentWood() * pillageFactor));
|
||||||
|
// this.map.getTownHall().addIron((int) (map.getTownHall().getCurrentIron() * pillageFactor));
|
||||||
|
// this.map.getTownHall().addGold((int) (map.getTownHall().getCurrentGold() * pillageFactor));
|
||||||
ChallengeAdapter adapter = new ChallengeAdapter(attacking);
|
ChallengeAdapter adapter = new ChallengeAdapter(attacking);
|
||||||
return adapter.attack(defending, simulated, pillageFactor, client);
|
adapter.attack(defending);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map generateInitialMap(){
|
public Map generateInitialMap(){
|
||||||
|
@ -143,27 +147,23 @@ public class GameEngine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized boolean build (Map map, String buildingArg) throws BuildingErrorException {
|
public synchronized boolean build (Map map, String buildingArg) {
|
||||||
BuildingFactory bfactory = new BuildingFactory();
|
BuildingFactory bfactory = new BuildingFactory();
|
||||||
Building type = bfactory.getBuilding(buildingArg);
|
Building type = bfactory.getBuilding(buildingArg);
|
||||||
if (type == null)
|
|
||||||
throw new BuildingErrorException("Invalid building type!");
|
|
||||||
return map.build(new Tile(), type);
|
return map.build(new Tile(), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean train (Map map, String inhabitantArgs) throws TrainingErrorException {
|
public boolean train (Map map, String inhabitantArgs) {
|
||||||
InhabitantFactory ifactory = new InhabitantFactory();
|
InhabitantFactory ifactory = new InhabitantFactory();
|
||||||
Inhabitant type = ifactory.getInhabitant(inhabitantArgs);
|
Inhabitant type = ifactory.getInhabitant(inhabitantArgs);
|
||||||
if (type == null)
|
|
||||||
throw new TrainingErrorException("Invalid training type!");
|
|
||||||
return map.train(type);
|
return map.train(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized boolean upgradeBuilding (Map map, int buildingIndex) throws UpgradingErrorException {
|
public synchronized boolean upgradeBuilding (Map map, int buildingIndex) {
|
||||||
return map.upgradeBuilding(buildingIndex);
|
return map.upgradeBuilding(buildingIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized boolean upgradeInhabitant (Map map, int inhabitantIndex) {
|
public boolean upgradeInhabitant (Map map, int inhabitantIndex) {
|
||||||
return map.upgradeInhabitant(inhabitantIndex);
|
return map.upgradeInhabitant(inhabitantIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,22 +279,4 @@ public class GameEngine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class BuildingErrorException extends Exception {
|
|
||||||
public BuildingErrorException(String message){
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TrainingErrorException extends Exception {
|
|
||||||
public TrainingErrorException(String message){
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class UpgradingErrorException extends Exception {
|
|
||||||
public UpgradingErrorException(String message){
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,20 +54,17 @@ public class Map implements Serializable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean upgradeBuilding(int buildingIndex) throws GameEngine.UpgradingErrorException {
|
public boolean upgradeBuilding(int buildingIndex) {
|
||||||
|
|
||||||
if (buildingIndex >= contains.size() || buildingIndex < 0)
|
if (buildingIndex >= contains.size() || buildingIndex < 0) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
Building b = contains.get(buildingIndex);
|
Building b = contains.get(buildingIndex);
|
||||||
|
|
||||||
int currentLevel = b.getLevel();
|
int currentLevel = b.getLevel();
|
||||||
CasaDeNarino hall = getTownHall();
|
CasaDeNarino hall = getTownHall();
|
||||||
|
|
||||||
if (currentLevel >= 2)
|
if (currentLevel >= 2) return false;
|
||||||
return false;
|
else if (b instanceof Farm) return true;
|
||||||
else if (b instanceof Farm)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
int goldCost = b.getUpgradeStage().getCost(SaulGoodMine.resource);
|
int goldCost = b.getUpgradeStage().getCost(SaulGoodMine.resource);
|
||||||
int ironCost = b.getUpgradeStage().getCost(IronMine.resource);
|
int ironCost = b.getUpgradeStage().getCost(IronMine.resource);
|
||||||
|
@ -89,8 +86,7 @@ public class Map implements Serializable {
|
||||||
} else {
|
} else {
|
||||||
b.upgrade(VillageHallStages.villageStages[currentLevel + 1]);
|
b.upgrade(VillageHallStages.villageStages[currentLevel + 1]);
|
||||||
}
|
}
|
||||||
} else
|
} else return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,10 @@ import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
public class GameDisplay {
|
public class GameDisplay {
|
||||||
private final BufferedReader reader;
|
private BufferedReader reader;
|
||||||
private String input;
|
private String input;
|
||||||
|
|
||||||
public GameDisplay() {
|
public GameDisplay() {
|
||||||
|
@ -31,7 +30,7 @@ public class GameDisplay {
|
||||||
System.out.println("\t->" + input + '\n');
|
System.out.println("\t->" + input + '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<String> getVillageStateTable(Map map, String displayName){
|
public void printVillageState(Map map, String displayName) {
|
||||||
Print resourcesPrinter = new Print(displayName, 2);
|
Print resourcesPrinter = new Print(displayName, 2);
|
||||||
|
|
||||||
resourcesPrinter.addColumn(new Print.Column("Resource Type"));
|
resourcesPrinter.addColumn(new Print.Column("Resource Type"));
|
||||||
|
@ -53,7 +52,7 @@ public class GameDisplay {
|
||||||
Integer.toString(map.getTownHall().getGoldCapacity()),
|
Integer.toString(map.getTownHall().getGoldCapacity()),
|
||||||
Integer.toString(map.getTownHall().getCurrentGold())));
|
Integer.toString(map.getTownHall().getCurrentGold())));
|
||||||
|
|
||||||
ArrayList<String> total = new ArrayList<>(resourcesPrinter.createTable(true, false, true));
|
Print.print(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 +64,7 @@ public class GameDisplay {
|
||||||
Integer.toString(b.getLevel() + 1),
|
Integer.toString(b.getLevel() + 1),
|
||||||
Integer.toString(b.getHealth())));
|
Integer.toString(b.getHealth())));
|
||||||
|
|
||||||
total.addAll(buildingPrinter.createTable(true, false, true));
|
Print.print(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,29 +73,17 @@ 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)));
|
||||||
|
|
||||||
total.addAll(inhabs.createTable(true, true, true));
|
Print.print(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) {
|
|
||||||
Print.print(getVillageStateTable(map, displayName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void printGameMenu() {
|
public void printGameMenu() {
|
||||||
System.out.println("\n\033[36m~ Player Options:\n" +
|
System.out.println("\n~ Player Options:\n" +
|
||||||
"1. Build {command: '1 <building name>'}\n" +
|
"1. Build {command: '1 <building name>'}\n" +
|
||||||
"2. Train inhabitants {command: '2 <unit name>'}\n"+
|
"2. Train inhabitants {command: '2 <unit name>'}\n"+
|
||||||
"3. Upgrade {command: '3 i<index>'} / {command: '3 b<index>'}\n"+
|
"3. Upgrade {command: '3 i<index>'} / {command: '3 b<index>'}\n"+
|
||||||
"4. Explore Player Villages\n"+
|
"4. Explore\n"+
|
||||||
"5. Print Village Stats\n"+
|
"5. Print Village Stats\n"+
|
||||||
"6. Quit\n" +
|
"6. Quit\n" +
|
||||||
"7. Attack last explored/generated\n" +
|
"7. Attack last explored\n");
|
||||||
"8. Generate Village\n" +
|
|
||||||
"9. Generate and Test Army\n" +
|
|
||||||
"0. Village Testing" +
|
|
||||||
"\033[0m\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,11 +3,9 @@ package ca.cosc3p91.a4.util;
|
||||||
import ChallengeDecision.*;
|
import ChallengeDecision.*;
|
||||||
import ca.cosc3p91.a4.game.Map;
|
import ca.cosc3p91.a4.game.Map;
|
||||||
import ca.cosc3p91.a4.gameobjects.*;
|
import ca.cosc3p91.a4.gameobjects.*;
|
||||||
import ca.cosc3p91.a4.util.network.Server;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
public class ChallengeAdapter {
|
public class ChallengeAdapter {
|
||||||
|
|
||||||
|
@ -81,7 +79,7 @@ public class ChallengeAdapter {
|
||||||
this.map = map;
|
this.map = map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean attack(Map enemy, boolean simulated, float pillageFactor, Server.ConnectedClient client){
|
public void attack(Map enemy){
|
||||||
MapChallengeConverter enemyMap = new MapChallengeConverter(enemy);
|
MapChallengeConverter enemyMap = new MapChallengeConverter(enemy);
|
||||||
MapChallengeConverter ourMap = new MapChallengeConverter(this.map);
|
MapChallengeConverter ourMap = new MapChallengeConverter(this.map);
|
||||||
|
|
||||||
|
@ -118,50 +116,28 @@ public class ChallengeAdapter {
|
||||||
|
|
||||||
// if any fail to attack we need to pretend like it was one big attack that failed
|
// if any fail to attack we need to pretend like it was one big attack that failed
|
||||||
if (!goldResults.getChallengeWon() || !ironResults.getChallengeWon() || !woodResults.getChallengeWon())
|
if (!goldResults.getChallengeWon() || !ironResults.getChallengeWon() || !woodResults.getChallengeWon())
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
System.out.print("We won gold: ");
|
System.out.println("We won gold: ");
|
||||||
goldResults.print();
|
goldResults.print();
|
||||||
System.out.print("We won iron: ");
|
System.out.println("We won iron: ");
|
||||||
ironResults.print();
|
ironResults.print();
|
||||||
System.out.print("We won wood: ");
|
System.out.println("We won wood: ");
|
||||||
woodResults.print();
|
woodResults.print();
|
||||||
|
|
||||||
CasaDeNarino th = map.getTownHall();
|
CasaDeNarino th = map.getTownHall();
|
||||||
CasaDeNarino eth = enemy.getTownHall();
|
|
||||||
|
|
||||||
AtomicInteger totalGold = new AtomicInteger();
|
goldResults.getLoot().forEach(r -> {
|
||||||
AtomicInteger totalIron = new AtomicInteger();
|
th.addGold((int)r.getProperty().doubleValue());
|
||||||
AtomicInteger totalWood = new AtomicInteger();
|
});
|
||||||
|
|
||||||
if (!simulated) {
|
ironResults.getLoot().forEach(r -> {
|
||||||
goldResults.getLoot().forEach(r -> {
|
th.addIron((int)r.getProperty().doubleValue());
|
||||||
int gold = (int) (r.getProperty() * pillageFactor);
|
});
|
||||||
th.addGold(gold);
|
|
||||||
eth.addGold(-gold);
|
|
||||||
totalGold.addAndGet(gold);
|
|
||||||
});
|
|
||||||
|
|
||||||
ironResults.getLoot().forEach(r -> {
|
woodResults.getLoot().forEach(r -> {
|
||||||
int iron = (int) (r.getProperty() * pillageFactor);
|
th.addWood((int)r.getProperty().doubleValue());
|
||||||
th.addIron(iron);
|
});
|
||||||
eth.addIron(-iron);
|
|
||||||
totalIron.addAndGet(iron);
|
|
||||||
});
|
|
||||||
|
|
||||||
woodResults.getLoot().forEach(r -> {
|
|
||||||
int wood = (int) (r.getProperty() * pillageFactor);
|
|
||||||
th.addWood(wood);
|
|
||||||
eth.addWood(-wood);
|
|
||||||
totalWood.addAndGet(wood);
|
|
||||||
});
|
|
||||||
|
|
||||||
client.sendAndLogLn("You won gold: " + totalGold.get());
|
|
||||||
client.sendAndLogLn("You won iron: " + totalIron.get());
|
|
||||||
client.sendAndLogLn("You won wood: " + totalWood.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,24 +9,17 @@ import java.net.DatagramPacket;
|
||||||
import java.net.DatagramSocket;
|
import java.net.DatagramSocket;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class Client implements Runnable {
|
public class Client implements Runnable {
|
||||||
private GameDisplay view = new GameDisplay();
|
private GameDisplay view = new GameDisplay();
|
||||||
|
|
||||||
private DatagramSocket clientSocket;
|
private DatagramSocket clientSocket;
|
||||||
private volatile boolean running = true;
|
private boolean running = true;
|
||||||
private Thread receiveThread;
|
private Thread receiveThread;
|
||||||
private final Map<Long, Message.Sent> sentMessages = Collections.synchronizedMap(new HashMap<>());
|
private final HashMap<Long, Message.Sent> sentMessages = 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;
|
|
||||||
|
|
||||||
public Client(String address) throws IOException {
|
public Client(String address) throws IOException {
|
||||||
serverAddress = InetAddress.getByName(address);
|
serverAddress = InetAddress.getByName(address);
|
||||||
|
@ -34,64 +27,35 @@ public class Client implements Runnable {
|
||||||
receiveThread = new Thread(this);
|
receiveThread = new Thread(this);
|
||||||
receiveThread.start();
|
receiveThread.start();
|
||||||
|
|
||||||
sendMessage(new Message.Sent(PacketIDs.CONNECT, ourClientID, ++lastMessageID));
|
sendMessage(new Message.Sent(PacketTable.CONNECT, 0, ++lastMessageID));
|
||||||
|
|
||||||
view.printGameMenu();
|
|
||||||
|
|
||||||
while (running) {
|
while (running) {
|
||||||
String prompt;
|
String prompt;
|
||||||
if ((prompt = view.nextInput()) != null) {
|
if ((prompt = view.nextInput()) != null) {
|
||||||
if (prompt.trim().isEmpty())
|
if (prompt.trim().isEmpty())
|
||||||
continue;
|
continue;
|
||||||
if (prompt.charAt(0) == '6') {
|
if (prompt.charAt(0) == '6')
|
||||||
running = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
view.printGameMenu();
|
|
||||||
String[] args = prompt.split(" ");
|
|
||||||
char c = prompt.charAt(0);
|
|
||||||
if (c > '0' && c < '4') {
|
|
||||||
if (args.length < 2) {
|
|
||||||
System.err.println("Args must include type!");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
byte messageType;
|
byte messageType;
|
||||||
switch (c) {
|
switch (prompt.charAt(0)) {
|
||||||
case '1':
|
case '1':
|
||||||
messageType = PacketIDs.BUILD;
|
messageType = PacketTable.BUILD;
|
||||||
break;
|
break;
|
||||||
case '2':
|
case '2':
|
||||||
messageType = PacketIDs.TRAIN;
|
messageType = PacketTable.TRAIN;
|
||||||
break;
|
break;
|
||||||
case '3':
|
case '3':
|
||||||
messageType = PacketIDs.UPGRADE;
|
messageType = PacketTable.UPGRADE;
|
||||||
break;
|
|
||||||
case '4':
|
|
||||||
messageType = PacketIDs.EXPLORE;
|
|
||||||
break;
|
|
||||||
case '5':
|
|
||||||
messageType = PacketIDs.PRINT_MAP_DATA;
|
|
||||||
break;
|
|
||||||
case '7':
|
|
||||||
messageType = PacketIDs.ATTACK;
|
|
||||||
break;
|
|
||||||
case '8':
|
|
||||||
messageType = PacketIDs.GENERATE;
|
|
||||||
break;
|
|
||||||
case '9':
|
|
||||||
messageType = PacketIDs.TEST_ARMY;
|
|
||||||
break;
|
|
||||||
case '0':
|
|
||||||
messageType = PacketIDs.TEST_VILLAGE;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
System.err.println("> Invalid command input!");
|
System.err.println("> Invalid command input!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Message.Sent buildMessage = new Message.Sent(messageType,ourClientID,++lastMessageID);
|
Message.Sent buildMessage = new Message.Sent(messageType,0,++lastMessageID);
|
||||||
buildMessage.getWriter().writeUTF(prompt.substring(1));
|
buildMessage.getData().write(prompt.substring(1).getBytes());
|
||||||
sendMessage(buildMessage);
|
sendMessage(buildMessage);
|
||||||
|
|
||||||
|
view.printGameMenu();
|
||||||
}
|
}
|
||||||
ArrayList<Long> removes = new ArrayList<>();
|
ArrayList<Long> removes = new ArrayList<>();
|
||||||
for (HashMap.Entry<Long, Message.Sent> message : sentMessages.entrySet()){
|
for (HashMap.Entry<Long, Message.Sent> message : sentMessages.entrySet()){
|
||||||
|
@ -121,12 +85,10 @@ public class Client implements Runnable {
|
||||||
long clientID = stream.readLong();
|
long clientID = stream.readLong();
|
||||||
long messageID = stream.readLong();
|
long messageID = stream.readLong();
|
||||||
|
|
||||||
System.out.println("Receiving message with ID " + messageID + " from server of type " + packetID + " our ClientID " + clientID + " / " + ourClientID);
|
System.out.println("Receiving message with ID " + messageID + " to client: " + clientID + " of type " + packetID);
|
||||||
|
|
||||||
switch (packetID) {
|
switch (packetID) {
|
||||||
case PacketIDs.ACK:
|
case PacketTable.ACK:
|
||||||
if (ourClientID == 0)
|
|
||||||
ourClientID = clientID;
|
|
||||||
Message.Sent message = sentMessages.get(messageID);
|
Message.Sent message = sentMessages.get(messageID);
|
||||||
if (message == null)
|
if (message == null)
|
||||||
throw new RuntimeException("Server acknowledged a message we never sent! (" + messageID + ")");
|
throw new RuntimeException("Server acknowledged a message we never sent! (" + messageID + ")");
|
||||||
|
@ -137,32 +99,11 @@ public class Client implements Runnable {
|
||||||
for (HashMap.Entry<Long, Message.Sent> ms : sentMessages.entrySet())
|
for (HashMap.Entry<Long, Message.Sent> ms : sentMessages.entrySet())
|
||||||
System.out.println("MessageID: " + ms.getKey());
|
System.out.println("MessageID: " + ms.getKey());
|
||||||
break;
|
break;
|
||||||
case PacketIDs.MESSAGE:
|
case PacketTable.DISCONNECT:
|
||||||
System.out.println("\033[93m" + stream.readUTF() + "\033[0m");
|
|
||||||
break;
|
|
||||||
case PacketIDs.BEGIN_MAP_DATA:
|
|
||||||
expectedLines = stream.readInt();
|
|
||||||
currentLines = 0;
|
|
||||||
lineBuffer = new String[expectedLines];
|
|
||||||
break;
|
|
||||||
case PacketIDs.MAP_LINE_DATA:
|
|
||||||
int lineNumber = stream.readInt();
|
|
||||||
lineBuffer[lineNumber] = stream.readUTF();
|
|
||||||
currentLines++;
|
|
||||||
if (currentLines >= expectedLines) {
|
|
||||||
for (String line : lineBuffer){
|
|
||||||
System.out.println("\033[92m" + line + "\033[0m");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PacketIDs.DISCONNECT:
|
|
||||||
System.out.println("Disconnecting!");
|
|
||||||
running = false;
|
running = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (packetID != PacketIDs.ACK && packetID != PacketIDs.DISCONNECT){
|
|
||||||
sendMessage(new Message.Sent(PacketIDs.ACK, ourClientID, messageID));
|
|
||||||
}
|
|
||||||
} catch (Exception e){
|
} catch (Exception e){
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -170,7 +111,7 @@ public class Client implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMessage(Message.Sent message){
|
private void sendMessage(Message.Sent message){
|
||||||
if (message.getPacketID() != PacketIDs.ACK)
|
if (message.getPacketID() != PacketTable.ACK)
|
||||||
sentMessages.put(message.getMessageID(), message);
|
sentMessages.put(message.getMessageID(), message);
|
||||||
byte[] data = message.getData().toByteArray();
|
byte[] data = message.getData().toByteArray();
|
||||||
DatagramPacket sendPacket = new DatagramPacket(data, data.length, serverAddress, Server.SERVER_PORT);
|
DatagramPacket sendPacket = new DatagramPacket(data, data.length, serverAddress, Server.SERVER_PORT);
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
package ca.cosc3p91.a4.util.network;
|
|
||||||
|
|
||||||
public class PacketIDs {
|
|
||||||
|
|
||||||
// packetID -> byte defined in this file
|
|
||||||
// clientID -> long
|
|
||||||
// messageID -> long
|
|
||||||
|
|
||||||
// MESSAGE_HEADER (packetID, clientID, messageID)
|
|
||||||
|
|
||||||
// MESSAGE_HEADER, (clientID = 0 if connecting to server)
|
|
||||||
public static final byte CONNECT = 0x1;
|
|
||||||
// MESSAGE_HEADER
|
|
||||||
public static final byte DISCONNECT = 0x2;
|
|
||||||
// MESSAGE_HEADER
|
|
||||||
public static final byte ACK = 0x3;
|
|
||||||
// MESSAGE_HEADER, UTF8 String with length information (use DOS.writeUTF/DIS.readUTF)
|
|
||||||
public static final byte MESSAGE = 0x4;
|
|
||||||
// MESSAGE_HEADER, build
|
|
||||||
public static final byte BUILD = 0x5;
|
|
||||||
// MESSAGE_HEADER, train
|
|
||||||
public static final byte TRAIN = 0x6;
|
|
||||||
// MESSAGE_HEADER, upgrade
|
|
||||||
public static final byte UPGRADE = 0x7;
|
|
||||||
// MESSAGE_HEADER
|
|
||||||
public static final byte PRINT_MAP_DATA = 0x8; // client -> server only!
|
|
||||||
// MESSAGE_HEADER, line count
|
|
||||||
public static final byte BEGIN_MAP_DATA = 0x9; // server -> client
|
|
||||||
// MESSAGE_HEADER, line number (int), UTF8 String (the line)
|
|
||||||
public static final byte MAP_LINE_DATA = 0xA; // server -> client
|
|
||||||
// MESSAGE_HEADER
|
|
||||||
public static final byte EXPLORE = 0xB;
|
|
||||||
// MESSAGE_HEADER
|
|
||||||
public static final byte ATTACK = 0xC;
|
|
||||||
// MESSAGE_HEADER
|
|
||||||
public static final byte GENERATE = 0xD;
|
|
||||||
// MESSAGE_HEADER
|
|
||||||
public static final byte TEST_ARMY = 0xE;
|
|
||||||
// MESSAGE_HEADER
|
|
||||||
public static final byte TEST_VILLAGE = 0xF;
|
|
||||||
}
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package ca.cosc3p91.a4.util.network;
|
||||||
|
|
||||||
|
public class PacketTable {
|
||||||
|
|
||||||
|
// packetID -> byte defined in this file
|
||||||
|
// clientID -> long
|
||||||
|
// messageID -> long
|
||||||
|
|
||||||
|
// messageHeader (packetID, clientID, messageID)
|
||||||
|
|
||||||
|
// messageHeader, (clientID = 0 if connecting to server)
|
||||||
|
public static final byte CONNECT = 0x1;
|
||||||
|
// messageHeader
|
||||||
|
public static final byte DISCONNECT = 0x2;
|
||||||
|
// messageHeader
|
||||||
|
public static final byte ACK = 0x3;
|
||||||
|
// messageHeader, UTF8 String with length information (use DOS.writeUTF/DIS.readUTF)
|
||||||
|
public static final byte MESSAGE = 0x4;
|
||||||
|
// messageHeader, build
|
||||||
|
public static final byte BUILD = 0x5;
|
||||||
|
// messageHeader, train
|
||||||
|
public static final byte TRAIN = 0x6;
|
||||||
|
// messageHeader, upgrade
|
||||||
|
public static final byte UPGRADE = 0x7;
|
||||||
|
// messageHeader, serial packets with map info
|
||||||
|
public static final byte USER_MAP_DATA = 0x8;
|
||||||
|
|
||||||
|
}
|
|
@ -2,15 +2,17 @@ package ca.cosc3p91.a4.util.network;
|
||||||
|
|
||||||
import ca.cosc3p91.a4.game.GameEngine;
|
import ca.cosc3p91.a4.game.GameEngine;
|
||||||
import ca.cosc3p91.a4.game.Map;
|
import ca.cosc3p91.a4.game.Map;
|
||||||
import ca.cosc3p91.a4.gameobjects.Infantry;
|
|
||||||
import ca.cosc3p91.a4.gameobjects.Inhabitant;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.rmi.ServerException;
|
import java.rmi.ServerException;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.HashMap;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
import java.util.Queue;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
@ -24,9 +26,9 @@ public class Server implements Runnable {
|
||||||
private long clientAssignmentID = 0;
|
private long clientAssignmentID = 0;
|
||||||
private final DatagramSocket socket;
|
private final DatagramSocket socket;
|
||||||
private final Thread ioThread;
|
private final Thread ioThread;
|
||||||
// private static volatile long lastSentMessageID = 0;
|
private long lastSentMessageID = 0;
|
||||||
|
|
||||||
private final GameEngine mainEngine;
|
private GameEngine mainEngine;
|
||||||
|
|
||||||
private volatile boolean running = true;
|
private volatile boolean running = true;
|
||||||
|
|
||||||
|
@ -53,20 +55,20 @@ public class Server implements Runnable {
|
||||||
long clientID = stream.readLong();
|
long clientID = stream.readLong();
|
||||||
long messageID = stream.readLong();
|
long messageID = stream.readLong();
|
||||||
|
|
||||||
System.out.println("Receiving message with ID " + messageID + " from client: " + clientID + " of type " + packetID);
|
System.out.println("Receiving message with ID " + messageID + " to client: " + clientID + " of type " + packetID);
|
||||||
|
|
||||||
ConnectedClient client = clients.get(clientID);
|
ConnectedClient client = clients.get(clientID);
|
||||||
|
|
||||||
// the server must handle connection requests while the client's processing thread will handle all other messages
|
// the server must handle connection requests while the client's processing thread will handle all other messages
|
||||||
if (packetID == PacketIDs.CONNECT){
|
if (packetID == PacketTable.CONNECT){
|
||||||
long cid = ++clientAssignmentID;
|
long cid = ++clientAssignmentID;
|
||||||
System.out.println("A client has connected, his clientID is " + cid);
|
System.out.println("A client has connected, his clientID is " + cid);
|
||||||
clients.put(cid, new ConnectedClient(this, mainEngine, cid, messageID, receivePacket.getAddress(), receivePacket.getPort()));
|
clients.put(cid, new ConnectedClient(socket, mainEngine, cid, messageID, receivePacket.getAddress(), receivePacket.getPort()));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (client == null)
|
if (client == null)
|
||||||
throw new ServerException("Client sent message invalid client id! (" + clientID + ")");
|
throw new ServerException("Client disconnected with invalid client id! (" + clientID + ")");
|
||||||
if (packetID == PacketIDs.DISCONNECT) {
|
if (packetID == PacketTable.DISCONNECT) {
|
||||||
client.halt();
|
client.halt();
|
||||||
clients.remove(clientID);
|
clients.remove(clientID);
|
||||||
continue;
|
continue;
|
||||||
|
@ -83,25 +85,27 @@ public class Server implements Runnable {
|
||||||
ioThread.join();
|
ioThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ConnectedClient implements Runnable {
|
public static void main(String[] args) throws IOException, InterruptedException {
|
||||||
|
new Server();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ConnectedClient implements Runnable {
|
||||||
private final InetAddress address;
|
private final InetAddress address;
|
||||||
private final int port;
|
private final int port;
|
||||||
private final Queue<Message.Received> pendingRequests = new LinkedBlockingQueue<>();
|
private final Queue<Message.Received> pendingRequests = new PriorityQueue<>();
|
||||||
private final ReentrantLock requestLock = new ReentrantLock();
|
private final ReentrantLock requestLock = new ReentrantLock();
|
||||||
private final AtomicBoolean allowUpdate;
|
private final AtomicBoolean allowUpdate;
|
||||||
private final java.util.Map<Long, Message.Sent> sentMessages = Collections.synchronizedMap(new HashMap<>());
|
private final HashMap<Long, Message.Sent> sentMessages = new HashMap<>();
|
||||||
private final Server server;
|
private final DatagramSocket serverSocket;
|
||||||
private final long clientID;
|
private final long clientID;
|
||||||
private volatile boolean running = true;
|
private volatile boolean running = true;
|
||||||
private final Thread processingThread;
|
private final Thread processingThread;
|
||||||
private final Thread gameEngineThread;
|
private final Thread gameEngineThread;
|
||||||
private final GameEngine usingEngine;
|
private final GameEngine usingEngine;
|
||||||
private long lastSentMessageID = 0;
|
|
||||||
private final Map clientMap;
|
private final Map clientMap;
|
||||||
private Map exploringMap;
|
|
||||||
|
|
||||||
public ConnectedClient(Server server, GameEngine engine, long clientID, long messageID, InetAddress address, int port){
|
public ConnectedClient(DatagramSocket serverSocket, GameEngine engine, long clientID, long messageID, InetAddress address, int port){
|
||||||
this.server = server;
|
this.serverSocket = serverSocket;
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.clientID = clientID;
|
this.clientID = clientID;
|
||||||
|
@ -119,7 +123,7 @@ public class Server implements Runnable {
|
||||||
});
|
});
|
||||||
gameEngineThread.start();
|
gameEngineThread.start();
|
||||||
|
|
||||||
sendMessage(new Message.Sent(PacketIDs.ACK, clientID, messageID));
|
sendMessage(new Message.Sent(PacketTable.ACK, clientID, messageID));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleRequest(Message.Received request){
|
public void handleRequest(Message.Received request){
|
||||||
|
@ -133,121 +137,27 @@ public class Server implements Runnable {
|
||||||
private void processRequest(Message.Received request){
|
private void processRequest(Message.Received request){
|
||||||
try {
|
try {
|
||||||
switch (request.getPacketID()) {
|
switch (request.getPacketID()) {
|
||||||
case PacketIDs.ACK:
|
case PacketTable.ACK:
|
||||||
Message.Sent message = sentMessages.get(request.getMessageID());
|
Message.Sent message = sentMessages.get(request.getMessageID());
|
||||||
if (message == null)
|
if (message == null)
|
||||||
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 PacketIDs.MESSAGE:
|
case PacketTable.MESSAGE:
|
||||||
System.out.println(request.getReader().readUTF());
|
System.out.println(request.getReader().readUTF());
|
||||||
break;
|
break;
|
||||||
case PacketIDs.BUILD:
|
case PacketTable.BUILD:
|
||||||
try {
|
usingEngine.build(clientMap,new String(request.getData(), StandardCharsets.UTF_8));
|
||||||
String type = request.getReader().readUTF().trim();
|
|
||||||
if (usingEngine.build(clientMap, type))
|
|
||||||
sendAndLogLn("Client " + clientID + " has successfully built " + type + "!");
|
|
||||||
else
|
|
||||||
sendAndLogLn("Client " + clientID + " has insufficient funds to build " + type + "!");
|
|
||||||
} catch (GameEngine.BuildingErrorException e){
|
|
||||||
sendAndLogLn(e.getMessage());
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case PacketIDs.TRAIN:
|
case PacketTable.TRAIN:
|
||||||
try {
|
usingEngine.train(clientMap,new String(request.getData(), StandardCharsets.UTF_8));
|
||||||
String type = request.getReader().readUTF().trim();
|
|
||||||
if (usingEngine.train(clientMap, type))
|
|
||||||
sendAndLogLn("Client " + clientID + " has successfully trained " + type + "!");
|
|
||||||
else
|
|
||||||
sendAndLogLn("Client " + clientID + " has insufficient funds to train " + type + "!");
|
|
||||||
} catch (GameEngine.TrainingErrorException e){
|
|
||||||
sendAndLogLn(e.getMessage());
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case PacketIDs.UPGRADE:
|
case PacketTable.UPGRADE:
|
||||||
try {
|
usingEngine.upgradeBuilding(clientMap, ByteBuffer.wrap(request.getData()).getInt());
|
||||||
String type = request.getReader().readUTF();
|
|
||||||
int val = Integer.parseInt(
|
|
||||||
type.replace("b", "")
|
|
||||||
.replace(" ", "")
|
|
||||||
.replace("i", "")
|
|
||||||
.trim());
|
|
||||||
boolean status = false;
|
|
||||||
if (type.contains("b"))
|
|
||||||
status = usingEngine.upgradeBuilding(clientMap, val);
|
|
||||||
else
|
|
||||||
status = usingEngine.upgradeInhabitant(clientMap, val);
|
|
||||||
if (status)
|
|
||||||
sendAndLogLn("Client " + clientID + " has successfully upgraded " + type + "!");
|
|
||||||
else
|
|
||||||
sendAndLogLn("Client " + clientID + " was unable to upgrade " + type + "!");
|
|
||||||
} catch (GameEngine.UpgradingErrorException e){
|
|
||||||
sendAndLogLn(e.getMessage());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PacketIDs.PRINT_MAP_DATA:
|
|
||||||
sendMapData(usingEngine.view.getVillageStateTable(clientMap, "Home Village"));
|
|
||||||
break;
|
|
||||||
case PacketIDs.EXPLORE:
|
|
||||||
Random rand = new Random();
|
|
||||||
int clients = server.clients.size();
|
|
||||||
if (clients <= 1) {
|
|
||||||
sendAndLogLn("No other clients are currently connected! Please generate a village!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int pos = rand.nextInt(clients);
|
|
||||||
long findingClientID = clientID;
|
|
||||||
ConnectedClient foundClient = null;
|
|
||||||
int searchCount = 0;
|
|
||||||
while (findingClientID == clientID) {
|
|
||||||
pos = rand.nextInt(clients);
|
|
||||||
Iterator<java.util.Map.Entry<Long, ConnectedClient>> entries = server.clients.entrySet().iterator();
|
|
||||||
for (int i = 0; i < pos; i++)
|
|
||||||
entries.next();
|
|
||||||
foundClient = entries.next().getValue();
|
|
||||||
findingClientID = foundClient.clientID;
|
|
||||||
if(searchCount++ > 50)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
exploringMap = foundClient.clientMap;
|
|
||||||
sendMapData(usingEngine.view.getVillageStateTable(exploringMap, "Other Village"));
|
|
||||||
break;
|
|
||||||
case PacketIDs.GENERATE:
|
|
||||||
exploringMap = usingEngine.generateMap(clientMap);
|
|
||||||
sendMapData(usingEngine.view.getVillageStateTable(exploringMap, "Generated Village"));
|
|
||||||
break;
|
|
||||||
case PacketIDs.ATTACK:
|
|
||||||
if (exploringMap != null) {
|
|
||||||
if (!usingEngine.attackVillage(clientMap, exploringMap, false,this))
|
|
||||||
sendAndLogLn("Failed to attack!");
|
|
||||||
} else
|
|
||||||
sendAndLogLn("Error: Explored map is null. Did you explored/generated last command?");
|
|
||||||
exploringMap = null;
|
|
||||||
break;
|
|
||||||
case PacketIDs.TEST_ARMY:
|
|
||||||
case PacketIDs.TEST_VILLAGE:
|
|
||||||
// said it had to be similar, not that it couldn't be the same!
|
|
||||||
Map m = usingEngine.generateInitialMap();
|
|
||||||
clientMap.inhabitants.stream().filter(i -> i instanceof Infantry).forEach(i -> {
|
|
||||||
m.inhabitants.add(i);
|
|
||||||
});
|
|
||||||
Random iamtired = new Random(69420);
|
|
||||||
int goodnight = iamtired.nextInt(69420 * 2 + 1) - 69420;
|
|
||||||
String asillynightmare = request.getPacketID() == PacketIDs.TEST_VILLAGE
|
|
||||||
? ("Your score was: " + String.valueOf(goodnight) + (goodnight <= 0 ? "! (you suck)" : "!"))
|
|
||||||
: "";
|
|
||||||
if (usingEngine.attackVillage(m, clientMap, true, this))
|
|
||||||
sendAndLogLn("Your village failed to defend! " + asillynightmare);
|
|
||||||
else
|
|
||||||
sendAndLogLn("Your village successfully defended itself from a similarly sized army! " + asillynightmare);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (request.getPacketID() != PacketIDs.ACK)
|
|
||||||
sendMessage(new Message.Sent(PacketIDs.ACK, clientID, request.getMessageID()));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@ -265,73 +175,22 @@ public class Server implements Runnable {
|
||||||
}
|
}
|
||||||
requestLock.unlock();
|
requestLock.unlock();
|
||||||
|
|
||||||
// sentEntries needn't be in the synchronized block
|
ArrayList<Long> removes = new ArrayList<>();
|
||||||
Set<HashMap.Entry<Long, Message.Sent>> sentEntries = sentMessages.entrySet();
|
for (HashMap.Entry<Long, Message.Sent> message : sentMessages.entrySet()){
|
||||||
synchronized (sentMessages) {
|
Message.Sent sent = message.getValue();
|
||||||
ArrayList<Long> removes = new ArrayList<>();
|
if (!sent.isAcknowledged() && sent.getTimeSinceSent().get() > MAX_PACKET_ACK_TIME_SECONDS) {
|
||||||
for (HashMap.Entry<Long, Message.Sent> message : sentEntries) {
|
System.out.println("The client did not acknowledge our message, did they receive it?");
|
||||||
Message.Sent sent = message.getValue();
|
sendMessage(sent);
|
||||||
if (!sent.isAcknowledged() && sent.getTimeSinceSent().get() > MAX_PACKET_ACK_TIME_SECONDS) {
|
removes.add(message.getKey());
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendMapData(ArrayList<String> lines) {
|
|
||||||
final long messageID = ++lastSentMessageID;
|
|
||||||
Message.Sent beginMapInfoMessage = new Message.Sent(PacketIDs.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 (Long l : removes)
|
||||||
for (int i = 0; i < lines.size(); i++){
|
sentMessages.remove(l);
|
||||||
Message.Sent line = new Message.Sent(PacketIDs.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();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendAndLogLn(String str){
|
|
||||||
Message.Sent mess = new Message.Sent(PacketIDs.MESSAGE, clientID, ++lastSentMessageID);
|
|
||||||
try {
|
|
||||||
mess.getWriter().writeUTF(str + "\n");
|
|
||||||
sendMessage(mess);
|
|
||||||
System.out.println(str);
|
|
||||||
} catch (IOException e){
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void sendMessage(Message.Sent message){
|
public void sendMessage(Message.Sent message){
|
||||||
if (message.getPacketID() != PacketIDs.ACK)
|
if (message.getPacketID() != PacketTable.ACK)
|
||||||
this.sentMessages.put(message.getMessageID(), message);
|
this.sentMessages.put(message.getMessageID(), message);
|
||||||
byte[] data = message.getData().toByteArray();
|
byte[] data = message.getData().toByteArray();
|
||||||
if (data.length > PACKET_SIZE)
|
if (data.length > PACKET_SIZE)
|
||||||
|
@ -339,7 +198,7 @@ public class Server implements Runnable {
|
||||||
DatagramPacket request = new DatagramPacket(data, data.length, address, port);
|
DatagramPacket request = new DatagramPacket(data, data.length, address, port);
|
||||||
try {
|
try {
|
||||||
System.out.println("Sending message with ID " + message.getMessageID() + " to client: " + message.getClientID() + " of type " + message.getPacketID());
|
System.out.println("Sending message with ID " + message.getMessageID() + " to client: " + message.getClientID() + " of type " + message.getPacketID());
|
||||||
server.socket.send(request);
|
serverSocket.send(request);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue