diff --git a/Assignment 4/src/ca/cosc3p91/a4/game/GameEngine.java b/Assignment 4/src/ca/cosc3p91/a4/game/GameEngine.java index fba0bc3..1ae1fca 100644 --- a/Assignment 4/src/ca/cosc3p91/a4/game/GameEngine.java +++ b/Assignment 4/src/ca/cosc3p91/a4/game/GameEngine.java @@ -13,30 +13,24 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.Random; -public class GameEngine implements Runnable { +public class GameEngine { public static final double GOLD_FACTOR = 5; public static final double IRON_FACTOR = 1; public static final double WOOD_FACTOR = 0.1; - private Player player; - boolean running = true; - private float pillageFactor = 0.5f; private int currentTime; private final Random random = new Random(System.nanoTime()); - public Map map; public GameDisplay view; public GameEngine() { - player = new Player(); - map = generateInitialMap(); } - public void attackVillage(Map map) { + public void attackVillage(Map attacking, Map defending) { // int defenseiveCounter = 1; // int inhabCounter = 0; // for (Building b : map.contains) @@ -53,31 +47,31 @@ public class GameEngine implements Runnable { // 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(this.map); - adapter.attack(map); + ChallengeAdapter adapter = new ChallengeAdapter(attacking); + adapter.attack(defending); } - private Map generateInitialMap(){ + public Map generateInitialMap(){ return new Map(new CasaDeNarino(1, VillageHallStages.villageStages[0]), 30); } - public Map generateMap() { + public Map generateMap(Map map) { Map initialMap = generateInitialMap(); CasaDeNarino hall = initialMap.getTownHall(); // generate a similar town hall int levelChange = random.nextInt(2) - 1; - int nextLevel = this.map.getTownHall().getLevel() + levelChange; + int nextLevel = map.getTownHall().getLevel() + levelChange; // only need to change if the new village level is higher than initial if (nextLevel > 0) hall.upgrade(VillageHallStages.villageStages[nextLevel]); - hall.addWood(this.map.getTownHall().getCurrentWood() + random.nextInt(500) - 150); - hall.addIron(this.map.getTownHall().getCurrentIron() + random.nextInt(500) - 150); - hall.addGold(this.map.getTownHall().getCurrentGold() + random.nextInt(500) - 150); + hall.addWood(map.getTownHall().getCurrentWood() + random.nextInt(500) - 150); + hall.addIron(map.getTownHall().getCurrentIron() + random.nextInt(500) - 150); + hall.addGold(map.getTownHall().getCurrentGold() + random.nextInt(500) - 150); - int buildingCount = this.map.contains.size(); + int buildingCount = map.contains.size(); int saulGoodMines = 0; int ironMines = 0; @@ -86,7 +80,7 @@ public class GameEngine implements Runnable { int cannons = 0; // count buildings in our map - for (Building b : this.map.contains){ + for (Building b : map.contains){ if (b instanceof SaulGoodMine) saulGoodMines++; else if (b instanceof IronMine) @@ -145,6 +139,35 @@ public class GameEngine implements Runnable { return score; } + public void updateMap(Map map) { + for (int i = 0; i < map.contains.size(); i++) { + if ((map.contains.get(i) instanceof ResourceBuilding)) { + ((ResourceBuilding) map.contains.get(i)).update(map.getTownHall()); + } + } + } + + public boolean build (Map map, String buildingArg) { + BuildingFactory bfactory = new BuildingFactory(); + Building type = bfactory.getBuilding(buildingArg); + return map.build(new Tile(), type); + } + + public boolean train (Map map, String inhabitantArgs) { + InhabitantFactory ifactory = new InhabitantFactory(); + Inhabitant type = ifactory.getInhabitant(inhabitantArgs); + return map.train(type); + } + + public boolean upgradeBuilding (Map map, int buildingIndex) { + return map.upgradeBuilding(buildingIndex); + } + + public boolean upgradeInhabitant (Map map, int inhabitantIndex) { + return map.upgradeInhabitant(inhabitantIndex); + } + + /* @Override public void run() { String in; @@ -156,11 +179,6 @@ public class GameEngine implements Runnable { Map exploringMap = null; boolean deleteMyHeart = true; while (running) { - for (Building b : this.map.contains){ - if ((b instanceof ResourceBuilding)) { - ((ResourceBuilding) b).update(this.map.getTownHall()); - } - } try { if ((in = view.nextInput()) != null) { String[] args = in.split(" "); @@ -249,8 +267,7 @@ public class GameEngine implements Runnable { if (deleteMyHeart) exploringMap = null; } - save("test.xml", this.map); - } + } */ public void save(String file, Map map){ try (XMLEncoder encoder = new XMLEncoder(new BufferedOutputStream(Files.newOutputStream(Paths.get(file))))) { diff --git a/Assignment 4/src/ca/cosc3p91/a4/game/Map.java b/Assignment 4/src/ca/cosc3p91/a4/game/Map.java index e03908f..fc0eaa6 100644 --- a/Assignment 4/src/ca/cosc3p91/a4/game/Map.java +++ b/Assignment 4/src/ca/cosc3p91/a4/game/Map.java @@ -56,7 +56,7 @@ public class Map implements Serializable { public boolean upgradeBuilding(int buildingIndex) { - if (buildingIndex >= contains.size()) return false; + if (buildingIndex >= contains.size() || buildingIndex < 0) return false; Building b = contains.get(buildingIndex); @@ -93,7 +93,7 @@ public class Map implements Serializable { public boolean upgradeInhabitant(int inhabitantIndex) { - if (inhabitantIndex >= inhabitants.size()) return false; + if (inhabitantIndex >= inhabitants.size() || inhabitantIndex < 0) return false; Inhabitant i = inhabitants.get(inhabitantIndex); diff --git a/Assignment 4/src/ca/cosc3p91/a4/util/network/PacketTable.java b/Assignment 4/src/ca/cosc3p91/a4/util/network/PacketTable.java index 9a56875..a97bdaf 100644 --- a/Assignment 4/src/ca/cosc3p91/a4/util/network/PacketTable.java +++ b/Assignment 4/src/ca/cosc3p91/a4/util/network/PacketTable.java @@ -16,5 +16,7 @@ public class PacketTable { public static final byte ACK = 0x3; // messageHeader, UTF8 String with length information (use DOS.writeUTF/DIS.readUTF) public static final byte MESSAGE = 0x4; + // messageHeader, serial packets with map info + public static final byte MAP_DATA = 0x5; } diff --git a/Assignment 4/src/ca/cosc3p91/a4/util/network/Server.java b/Assignment 4/src/ca/cosc3p91/a4/util/network/Server.java index 22f799a..51b605f 100644 --- a/Assignment 4/src/ca/cosc3p91/a4/util/network/Server.java +++ b/Assignment 4/src/ca/cosc3p91/a4/util/network/Server.java @@ -1,11 +1,16 @@ package ca.cosc3p91.a4.util.network; import ca.cosc3p91.a4.game.GameEngine; +import ca.cosc3p91.a4.game.Map; import java.io.*; import java.net.*; import java.rmi.ServerException; -import java.util.*; + +import java.util.HashMap; +import java.util.PriorityQueue; +import java.util.Queue; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; public class Server implements Runnable { @@ -49,7 +54,7 @@ public class Server implements Runnable { // the server must handle connection requests while the client's processing thread will handle all other messages if (packetID == PacketTable.CONNECT){ - clients.put(++clientAssignmentID, new ConnectedClient(socket, clientID, messageID, receivePacket.getAddress(), receivePacket.getPort())); + clients.put(++clientAssignmentID, new ConnectedClient(socket, mainEngine, clientID, messageID, receivePacket.getAddress(), receivePacket.getPort())); } else if (packetID == PacketTable.DISCONNECT) { if (client == null) throw new ServerException("Client disconnected with invalid client id! (" + clientID + ")"); @@ -80,19 +85,32 @@ public class Server implements Runnable { private final int port; private final Queue pendingRequests = new PriorityQueue<>(); private final ReentrantLock requestLock = new ReentrantLock(); + private final AtomicBoolean allowUpdate; private final HashMap sentMessages = new HashMap<>(); private final DatagramSocket serverSocket; private final long clientID; private volatile boolean running = true; private final Thread processingThread; + private final Thread gameEngineThread; + private final Map clientMap; - public ConnectedClient(DatagramSocket serverSocket, long clientID, long messageID, InetAddress address, int port){ + public ConnectedClient(DatagramSocket serverSocket, GameEngine engine, long clientID, long messageID, InetAddress address, int port){ this.serverSocket = serverSocket; this.address = address; this.port = port; this.clientID = clientID; + this.clientMap = engine.generateInitialMap(); + this.allowUpdate = new AtomicBoolean(true); processingThread = new Thread(this); processingThread.start(); + gameEngineThread = new Thread(() -> { + while (true) { + if (this.allowUpdate.get()) { + engine.updateMap(clientMap); + } + } + }); + gameEngineThread.start(); sendMessage(new Message.Sent(PacketTable.ACK, clientID, messageID)); } @@ -129,11 +147,13 @@ public class Server implements Runnable { requestLock.lock(); if (!pendingRequests.isEmpty()) { Message.Received request = pendingRequests.remove(); + allowUpdate.set(false); processRequest(request); + allowUpdate.set(true); } requestLock.unlock(); - for (Map.Entry message : sentMessages.entrySet()){ + for (HashMap.Entry message : sentMessages.entrySet()){ if (message.getValue().getTimeSinceSent().get() > MAX_PACKET_ACK_TIME_SECONDS) { System.out.println("The server did not process our message, did they receive it?"); sendMessage(message.getValue());