diff --git a/src/main/java/com/han/asd/DungeonGame.java b/src/main/java/com/han/asd/DungeonGame.java
deleted file mode 100644
index 750c12cda3ce05ee703736a26afc12f306c57cd1..0000000000000000000000000000000000000000
--- a/src/main/java/com/han/asd/DungeonGame.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.han.asd;
-
-import com.han.asd.listener.ConnectionPacketListener;
-import com.han.asd.listener.DisconnectPacketListener;
-import com.han.asd.network.Network;
-import com.han.asd.network.exceptions.ConnectionFailedException;
-import com.han.asd.network.exceptions.DisconnectFailedException;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import java.net.SocketException;
-import java.net.UnknownHostException;
-
-public class DungeonGame {
-    private static final Logger logger = LogManager.getLogger(DungeonGame.class);
-    private final Network network;
-
-    public DungeonGame() throws UnknownHostException {
-        this.network = new Network();
-    }
-
-    public void createLobby() throws ConnectionFailedException, SocketException, UnknownHostException {
-        network.startLobby(Main.TEST_DUNGEON_PORT);
-
-        network.getPacketDispatcher().register(new ConnectionPacketListener());
-        network.getPacketDispatcher().register(new DisconnectPacketListener());
-
-        logger.info("Lobby created and started on port {}", Main.TEST_DUNGEON_PORT);
-    }
-
-    public void stopLobby() {
-        network.stopLobby();
-        logger.info("Lobby stopped");
-    }
-
-    public void discover() {
-        network.startDiscovery(Main.TEST_DUNGEON_PORT);
-        logger.info("Started discovery to join lobby");
-    }
-
-    public void joinLobby(String ip) throws ConnectionFailedException {
-        network.connectLobby(ip, Main.TEST_DUNGEON_PORT);
-        logger.info("Started discovery to join lobby");
-    }
-
-    public void leaveLobby() throws DisconnectFailedException {
-        network.disconnectLobby();
-        logger.info("Left the lobby");
-    }
-
-    public Network getNetwork() {
-        return network;
-    }
-}
diff --git a/src/main/java/com/han/asd/Main.java b/src/main/java/com/han/asd/Main.java
index 3cc9248575b773aedcad51e6bb264de1b554d521..7c694da7191d528f0a7ea82def325e90a52cae4d 100644
--- a/src/main/java/com/han/asd/Main.java
+++ b/src/main/java/com/han/asd/Main.java
@@ -1,47 +1,60 @@
 package com.han.asd;
 
-import com.han.asd.network.exceptions.ConnectionFailedException;
-import com.han.asd.network.exceptions.DisconnectFailedException;
-import com.han.asd.network.exceptions.NetworkConfigurationException;
+import com.han.asd.api.network.discovery.Discovery;
+import com.han.asd.api.network.exceptions.ConnectionFailedException;
+import com.han.asd.api.network.exceptions.DisconnectFailedException;
+import com.han.asd.api.network.exceptions.SendFailedException;
+import com.han.asd.api.network.packet.Packet;
+import com.han.asd.game.DungeonGame;
+import com.han.asd.packets.ConnectionPacket;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
-import java.net.SocketException;
-import java.net.UnknownHostException;
+import java.io.IOException;
 
 public class Main {
-    public static final int TEST_DUNGEON_PORT = 8886;
-    public static final int TEST_DUNGEON_PORT_2 = 8887;
     private static final Logger logger = LogManager.getLogger(Main.class);
 
-    public static void main(String[] args)
-            throws InterruptedException, DisconnectFailedException, UnknownHostException, NetworkConfigurationException, ConnectionFailedException, SocketException {
+    public static void main(String[] args) throws IOException, ConnectionFailedException, InterruptedException, DisconnectFailedException, SendFailedException {
         logger.info("Starting DungeonGame application...");
 
+        // Create a game (network for host)
         DungeonGame dungeonGame = new DungeonGame();
-//        dungeonGame.createLobby();
-//        logger.info("Lobby created successfully.");
+        dungeonGame.createGame();
 
-        dungeonGame.discover();
-        logger.info("Attempting to discover lobby(s)...");
+        // Simulate wait time
+        Thread.sleep(3000);
 
-        Thread.sleep(1000*60);
+        // Discover hosts for 3 seconds
+        dungeonGame.discoverGames(3000);
 
-        if (!dungeonGame.getNetwork().getHosts().isEmpty()) {
-            logger.info("Lobby(s) have been found, joining the first one as a test.");
+        // TUI would print found games.
+        Discovery discovery = dungeonGame.getNetwork().getDiscovery();
+        for (String host : discovery.getHosts()) {
+            logger.info("{}", host);
+        }
 
-            String lobbyIp = dungeonGame.getNetwork().getHosts().get(0);
-            dungeonGame.joinLobby(lobbyIp);
+        // Simulate joining a game
+        if(!discovery.getHosts().isEmpty()) {
+            String serverIpToJoin = discovery.getHosts().getFirst();
+            if(serverIpToJoin != null) {
+                // Join the game (connect to a host)
+                dungeonGame.joinGame(serverIpToJoin);
+            }
 
-            Thread.sleep(3000);
+            // Simulate wait time
+            Thread.sleep(2000);
 
-            dungeonGame.leaveLobby();
-            logger.info("Leaving the lobby...");
+            // Leave the game (disconnect from host)
+            dungeonGame.leaveGame();
         } else {
-            logger.info("No lobby(s) where found during the discovery.");
+            logger.info("No lobby found.");
         }
 
-//        dungeonGame.stopLobby();
-//        logger.info("Lobby stopped. Exiting application.");
+        // Simulate wait time
+        Thread.sleep(2000);
+
+        // Stop the game (network for host)
+        dungeonGame.stopGame();
     }
 }
diff --git a/src/main/java/com/han/asd/api/network/HostNetwork.java b/src/main/java/com/han/asd/api/network/HostNetwork.java
new file mode 100644
index 0000000000000000000000000000000000000000..be148117b6b07efef5ded90af1a8dd20e5f428f5
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/HostNetwork.java
@@ -0,0 +1,28 @@
+package com.han.asd.api.network;
+
+import com.han.asd.api.network.exceptions.ConnectionFailedException;
+import com.han.asd.api.network.server.TCPServer;
+import com.han.asd.api.network.tick.TickManager;
+import com.han.asd.api.threading.ThreadManager;
+
+public class HostNetwork {
+    private final TickManager tickManager;
+    private final ThreadManager threadManager;
+    private TCPServer hostServer;
+
+    public HostNetwork(TickManager tickManager, ThreadManager threadManager) {
+        this.threadManager = threadManager;
+        this.tickManager = tickManager;
+    }
+
+    public void startHost(int port) throws ConnectionFailedException {
+        hostServer = new TCPServer(threadManager, tickManager);
+        hostServer.start(port);
+
+        threadManager.runOperation(hostServer);
+    }
+
+    public void stopHost() {
+        threadManager.stopOperation(hostServer);
+    }
+}
diff --git a/src/main/java/com/han/asd/api/network/Network.java b/src/main/java/com/han/asd/api/network/Network.java
new file mode 100644
index 0000000000000000000000000000000000000000..adc3f1acbf2eaf4a417714c54f3f8d1ab012c6b5
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/Network.java
@@ -0,0 +1,34 @@
+package com.han.asd.api.network;
+
+import com.han.asd.api.network.HostNetwork;
+import com.han.asd.api.network.connection.ConnectionHandler;
+import com.han.asd.api.network.connection.TCPConnection;
+import com.han.asd.api.network.discovery.Discovery;
+import com.han.asd.api.network.exceptions.ConnectionFailedException;
+import com.han.asd.api.network.exceptions.DisconnectFailedException;
+import com.han.asd.api.network.exceptions.SendFailedException;
+import com.han.asd.api.network.packet.Packet;
+import com.han.asd.api.network.packet.PacketDispatcher;
+import com.han.asd.api.network.tick.TickManager;
+import com.han.asd.api.threading.ThreadManager;
+import com.han.asd.packets.ConnectionPacket;
+
+import java.net.Socket;
+
+public interface Network {
+    HostNetwork getHostNetwork();
+    PacketDispatcher getPacketDispatcher();
+    TickManager getTickManager();
+    ThreadManager getThreadManager();
+    ConnectionHandler getConnectionHandler();
+    Discovery getDiscovery();
+    int getDiscoveryServerPort();
+    int getDiscoveryClientPort();
+    String getDiscoveryAddress();
+    int getTickCount();
+    void startHost() throws ConnectionFailedException;
+    void stopHost();
+    void discoverHosts(int timeout);
+    void connectHost(String address) throws ConnectionFailedException;
+    void disconnectHost() throws DisconnectFailedException;
+}
diff --git a/src/main/java/com/han/asd/api/network/connection/Connection.java b/src/main/java/com/han/asd/api/network/connection/Connection.java
new file mode 100644
index 0000000000000000000000000000000000000000..c64a79ad80c7dfd547e30d6baf17b194944acbce
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/connection/Connection.java
@@ -0,0 +1,13 @@
+package com.han.asd.api.network.connection;
+
+import com.han.asd.api.network.exceptions.PacketParsingException;
+import com.han.asd.api.network.exceptions.ReceiveFailedException;
+import com.han.asd.api.network.exceptions.SendFailedException;
+import com.han.asd.api.network.packet.Packet;
+
+public interface Connection {
+    void send(Packet packet) throws SendFailedException;
+    Packet receive() throws PacketParsingException, ReceiveFailedException;
+    void close();
+    boolean isConnected();
+}
diff --git a/src/main/java/com/han/asd/api/network/connection/ConnectionHandler.java b/src/main/java/com/han/asd/api/network/connection/ConnectionHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..99d6b7449ef623a9b99707e1ccff59c04663cb65
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/connection/ConnectionHandler.java
@@ -0,0 +1,59 @@
+package com.han.asd.api.network.connection;
+
+import com.han.asd.api.network.exceptions.PacketParsingException;
+import com.han.asd.api.network.exceptions.ReceiveFailedException;
+import com.han.asd.api.network.packet.Packet;
+import com.han.asd.api.network.tick.TickManager;
+import com.han.asd.api.threading.operation.Operation;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ConnectionHandler implements Operation {
+    private static final Logger logger = LogManager.getLogger(ConnectionHandler.class);
+    private final TickManager tickManager;
+    private final Connection connection;
+
+    public ConnectionHandler(TickManager tickManager, Connection connection) {
+        this.tickManager = tickManager;
+        this.connection = connection;
+    }
+
+    @Override
+    public void stop() {
+        connection.close();
+    }
+
+    @Override
+    public void execute() {
+        try {
+            while (!Thread.interrupted() && connection.isConnected()) {
+                Packet packet = connection.receive();
+                if(packet != null) {
+                    tickManager.getQueue().add(packet);
+                    logger.info("Packet added to queue: {}", packet.getClass().getSimpleName());
+                } else if(!connection.isConnected()) {
+                    break;
+                }
+                Thread.sleep(1);
+            }
+        } catch (ReceiveFailedException | PacketParsingException e) {
+            logger.error("Invalid packet exception in connection handler", e);
+            throw new RuntimeException("InvalidPacketException occurred", e);
+        } catch (InterruptedException ignored) {
+        }
+    }
+
+    @Override
+    public long getTimeout() {
+        return 1;
+    }
+
+    @Override
+    public int getPriority() {
+        return 0;
+    }
+
+    public Connection getConnection() {
+        return connection;
+    }
+}
diff --git a/src/main/java/com/han/asd/network/connection/TCPConnection.java b/src/main/java/com/han/asd/api/network/connection/TCPConnection.java
similarity index 70%
rename from src/main/java/com/han/asd/network/connection/TCPConnection.java
rename to src/main/java/com/han/asd/api/network/connection/TCPConnection.java
index 03b0c1ca091cd19458366e36b8b2379c00f20e2c..5492ea54b24f55477c2fb0c0221e58df14cd2901 100644
--- a/src/main/java/com/han/asd/network/connection/TCPConnection.java
+++ b/src/main/java/com/han/asd/api/network/connection/TCPConnection.java
@@ -1,13 +1,14 @@
-package com.han.asd.network.connection;
+package com.han.asd.api.network.connection;
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
-import com.han.asd.network.exceptions.PacketParsingException;
-import com.han.asd.network.exceptions.ReceiveFailedException;
-import com.han.asd.network.exceptions.SendFailedException;
-import com.han.asd.network.packet.Packet;
+import com.han.asd.api.network.exceptions.ConnectionFailedException;
+import com.han.asd.api.network.exceptions.PacketParsingException;
+import com.han.asd.api.network.exceptions.ReceiveFailedException;
+import com.han.asd.api.network.exceptions.SendFailedException;
+import com.han.asd.api.network.packet.Packet;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -16,20 +17,21 @@ import java.lang.reflect.Type;
 import java.net.Socket;
 
 public class TCPConnection implements Connection {
-
     private static final Logger logger = LogManager.getLogger(TCPConnection.class);
-
     private final Gson gson;
     private Socket socket;
     private BufferedReader reader;
     private BufferedWriter writer;
 
-    public TCPConnection(Socket socket) throws IOException {
-        this.socket = socket;
-        this.gson = new GsonBuilder().create();
-        this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
-        this.writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
-        logger.info("TCP connection established with {}:{}", socket.getInetAddress().getHostAddress(), socket.getPort());
+    public TCPConnection(Socket socket) throws ConnectionFailedException {
+        try {
+            this.socket = socket;
+            this.gson = new GsonBuilder().create();
+            this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+            this.writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
+        } catch (IOException e) {
+            throw new ConnectionFailedException("Failed to open input/output stream", e);
+        }
     }
 
     @Override
@@ -44,6 +46,7 @@ public class TCPConnection implements Connection {
             writer.write(rawPacket);
             writer.newLine();
             writer.flush();
+
             logger.debug("Packet sent: {}", packet.getClass().getSimpleName());
         } catch (IOException e) {
             logger.error("Error sending packet", e);
@@ -52,8 +55,11 @@ public class TCPConnection implements Connection {
     }
 
     @Override
-    public Packet receive() throws PacketParsingException, ReceiveFailedException {
+    public Packet receive() throws PacketParsingException {
         try {
+            if(socket == null || socket.isClosed() || !reader.ready())
+                return null;
+
             String rawPacket = reader.readLine();
             if (rawPacket == null) {
                 throw new PacketParsingException("Raw packet is empty.");
@@ -70,20 +76,18 @@ public class TCPConnection implements Connection {
         } catch (ClassNotFoundException | PacketParsingException e) {
             logger.error("Couldn't transform raw json into a valid packet.", e);
             throw new PacketParsingException("Couldn't transform raw json into a valid packet.", e);
-        } catch (IOException e) {
-            logger.error("Error receiving packet", e);
-            throw new ReceiveFailedException("Failed to receive TCP packet", e);
+        } catch (IOException ignored) {
+            //logger.error("Error receiving packet", e);
+            //throw new ReceiveFailedException("Failed to receive TCP packet", e);
         }
+
+        return null;
     }
 
     @Override
     public void close() {
         try {
-            //socket.shutdownInput();
-            //socket.shutdownOutput();
-
             if (reader != null) {
-                reader.reset();
                 reader.close();
             }
             if (writer != null) {
@@ -95,8 +99,6 @@ public class TCPConnection implements Connection {
         } catch (Exception ignored) {
             logger.error("Failed to drop connection");
         } finally {
-            logger.info("TCP connection closed");
-
             socket = null;
             reader = null;
             writer = null;
diff --git a/src/main/java/com/han/asd/network/connection/UDPConnection.java b/src/main/java/com/han/asd/api/network/connection/UDPConnection.java
similarity index 90%
rename from src/main/java/com/han/asd/network/connection/UDPConnection.java
rename to src/main/java/com/han/asd/api/network/connection/UDPConnection.java
index a39c0e9222e43a1c3fb76306d95525fe49fc48fe..93132012f56bcda5b67d66c23a0ed9480715b973 100644
--- a/src/main/java/com/han/asd/network/connection/UDPConnection.java
+++ b/src/main/java/com/han/asd/api/network/connection/UDPConnection.java
@@ -1,151 +1,155 @@
-package com.han.asd.network.connection;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.han.asd.network.exceptions.NetworkConfigurationException;
-import com.han.asd.network.exceptions.PacketParsingException;
-import com.han.asd.network.exceptions.ReceiveFailedException;
-import com.han.asd.network.exceptions.SendFailedException;
-import com.han.asd.network.packet.Packet;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import java.io.IOException;
-import java.lang.reflect.Type;
-import java.net.*;
-import java.util.Collections;
-import java.util.Enumeration;
-
-public class UDPConnection implements Connection {
-    private static final Logger logger = LogManager.getLogger(UDPConnection.class);
-
-    private final Gson gson;
-    private final DatagramSocket datagramSocket;
-    private final InetAddress address;
-    private final int port;
-    private boolean connected;
-
-    public UDPConnection(DatagramSocket datagramSocket, InetAddress address, int port) {
-        this.datagramSocket = datagramSocket;
-        this.gson = new GsonBuilder().create();
-        this.address = address;
-        this.port = port;
-        this.connected = true;
-    }
-
-    public UDPConnection(DatagramSocket datagramSocket) {
-        this(datagramSocket, datagramSocket.getInetAddress(), datagramSocket.getLocalPort());
-    }
-
-    public UDPConnection(InetAddress address, int port) throws SocketException {
-        this(new DatagramSocket(), address, port);
-    }
-
-    public UDPConnection(int port) throws SocketException, NetworkConfigurationException {
-        this(getLocalBroadcastAddress(), port);
-    }
-
-    public static InetAddress getLocalBroadcastAddress() throws NetworkConfigurationException {
-        try {
-            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
-            for (NetworkInterface netInt : Collections.list(networkInterfaces)) {
-                if (netInt.isLoopback() || !netInt.isUp())
-                    continue;
-
-                for (InterfaceAddress interfaceAddress : netInt.getInterfaceAddresses()) {
-                    InetAddress broadcast = interfaceAddress.getBroadcast();
-                    if (broadcast == null)
-                        continue;
-
-                    if (interfaceAddress.getAddress().equals(InetAddress.getLocalHost())) {
-                        return broadcast;
-                    }
-                }
-            }
-        } catch (SocketException | UnknownHostException e) {
-            throw new NetworkConfigurationException("Socket initialization failed", e);
-        }
-        return null;
-    }
-
-    public void broadcast(Packet packet) throws SendFailedException, NetworkConfigurationException {
-        InetAddress broadcastAddress = getLocalBroadcastAddress();
-        if (broadcastAddress != null) {
-            send(broadcastAddress, packet);
-            logger.info("Broadcast packet sent");
-        } else {
-            logger.error("Broadcast address not found");
-        }
-    }
-
-    @Override
-    public void send(Packet packet) throws SendFailedException {
-        send(address, packet);
-    }
-
-    private void send(InetAddress address, Packet packet) throws SendFailedException {
-        try {
-            JsonObject wrapper = new JsonObject();
-            wrapper.addProperty("type", packet.getClass().getName());
-            wrapper.add("data", gson.toJsonTree(packet));
-
-            String rawPacket = wrapper.toString();
-            byte[] buffer = rawPacket.getBytes();
-
-            DatagramPacket networkPacket = new DatagramPacket(buffer, buffer.length, address, port);
-            datagramSocket.send(networkPacket);
-
-            logger.info("Packet sent to: {}", address.getHostAddress());
-        } catch (IOException e) {
-            logger.error("Error sending packet", e);
-            throw new SendFailedException("Error sending packet", e);
-        }
-    }
-
-    @Override
-    public Packet receive() throws PacketParsingException, ReceiveFailedException {
-        try {
-            byte[] buffer = new byte[1024];
-            DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);
-            datagramSocket.receive(datagramPacket);
-
-            String rawPacket = new String(datagramPacket.getData(), 0, datagramPacket.getLength());
-            if (rawPacket.isEmpty()) {
-                throw new PacketParsingException("Raw packet is empty.");
-            }
-
-            JsonObject member = gson.fromJson(rawPacket, JsonObject.class);
-            JsonElement typeString = member.get("type");
-            JsonElement data = member.get("data");
-
-            Type packetType = Class.forName(typeString.getAsString());
-            Packet packet = gson.fromJson(data, packetType);
-
-            logger.info("Packet received: {}", packet.getClass().getSimpleName());
-            return packet;
-        } catch (ClassNotFoundException | PacketParsingException e) {
-            logger.error("Couldn't transform raw json into a valid packet.", e);
-            throw new PacketParsingException("Couldn't transform raw json into a valid packet.", e);
-        } catch (SocketException e) {
-        } catch (Exception e) {
-            logger.error("Error receiving packet");
-            throw new ReceiveFailedException("Failed to receive UDP packet", e);
-        }
-
-        return null;
-    }
-
-    @Override
-    public void close() {
-        datagramSocket.close();
-        connected = false;
-        logger.info("UDP connection closed");
-    }
-
-    @Override
-    public boolean isConnected() {
-        return connected;
-    }
-}
+package com.han.asd.api.network.connection;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.han.asd.api.network.exceptions.NetworkConfigurationException;
+import com.han.asd.api.network.exceptions.PacketParsingException;
+import com.han.asd.api.network.exceptions.ReceiveFailedException;
+import com.han.asd.api.network.exceptions.SendFailedException;
+import com.han.asd.api.network.packet.Packet;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.net.*;
+import java.util.Collections;
+import java.util.Enumeration;
+
+public class UDPConnection implements Connection {
+    private static final Logger logger = LogManager.getLogger(UDPConnection.class);
+
+    private final Gson gson;
+    private final DatagramSocket datagramSocket;
+    private final InetAddress address;
+    private final int port;
+    private boolean connected;
+
+    public UDPConnection(DatagramSocket datagramSocket, InetAddress address, int port) {
+        this.datagramSocket = datagramSocket;
+        this.gson = new GsonBuilder().create();
+        this.address = address;
+        this.port = port;
+        this.connected = true;
+    }
+
+    public UDPConnection(DatagramSocket datagramSocket) {
+        this(datagramSocket, datagramSocket.getInetAddress(), datagramSocket.getLocalPort());
+    }
+
+    public UDPConnection(InetAddress address, int port) throws SocketException {
+        this(new DatagramSocket(), address, port);
+    }
+
+    public UDPConnection(int port) throws SocketException, NetworkConfigurationException {
+        this(getLocalBroadcastAddress(), port);
+    }
+
+    public static InetAddress getLocalBroadcastAddress() throws NetworkConfigurationException {
+        try {
+            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
+            for (NetworkInterface netInt : Collections.list(networkInterfaces)) {
+                if (netInt.isLoopback() || !netInt.isUp())
+                    continue;
+
+                for (InterfaceAddress interfaceAddress : netInt.getInterfaceAddresses()) {
+                    InetAddress broadcast = interfaceAddress.getBroadcast();
+                    if (broadcast == null)
+                        continue;
+
+                    if (interfaceAddress.getAddress().equals(InetAddress.getLocalHost())) {
+                        return broadcast;
+                    }
+                }
+            }
+        } catch (SocketException | UnknownHostException e) {
+            throw new NetworkConfigurationException("Socket initialization failed", e);
+        }
+        return null;
+    }
+
+    public void broadcast(Packet packet) throws SendFailedException, NetworkConfigurationException {
+        InetAddress broadcastAddress = getLocalBroadcastAddress();
+        if (broadcastAddress != null) {
+            send(broadcastAddress, packet);
+            logger.info("Broadcast packet sent");
+        } else {
+            logger.error("Broadcast address not found");
+        }
+    }
+
+    @Override
+    public void send(Packet packet) throws SendFailedException {
+        send(address, packet);
+    }
+
+    private void send(InetAddress address, Packet packet) throws SendFailedException {
+        try {
+            JsonObject wrapper = new JsonObject();
+            wrapper.addProperty("type", packet.getClass().getName());
+            wrapper.add("data", gson.toJsonTree(packet));
+
+            String rawPacket = wrapper.toString();
+            byte[] buffer = rawPacket.getBytes();
+
+            DatagramPacket networkPacket = new DatagramPacket(buffer, buffer.length, address, port);
+            datagramSocket.send(networkPacket);
+
+            logger.info("Packet sent to: {}", address.getHostAddress());
+        } catch (IOException e) {
+            logger.error("Error sending packet", e);
+            throw new SendFailedException("Error sending packet", e);
+        }
+    }
+
+    @Override
+    public Packet receive() throws PacketParsingException, ReceiveFailedException {
+        try {
+            byte[] buffer = new byte[1024];
+            DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);
+            datagramSocket.receive(datagramPacket);
+
+            String rawPacket = new String(datagramPacket.getData(), 0, datagramPacket.getLength());
+            if (rawPacket.isEmpty()) {
+                throw new PacketParsingException("Raw packet is empty.");
+            }
+
+            JsonObject member = gson.fromJson(rawPacket, JsonObject.class);
+            JsonElement typeString = member.get("type");
+            JsonElement data = member.get("data");
+
+            Type packetType = Class.forName(typeString.getAsString());
+            Packet packet = gson.fromJson(data, packetType);
+
+            logger.info("Packet received: {}", packet.getClass().getSimpleName());
+            return packet;
+        } catch (ClassNotFoundException | PacketParsingException e) {
+            logger.error("Couldn't transform raw json into a valid packet.", e);
+            throw new PacketParsingException("Couldn't transform raw json into a valid packet.", e);
+        } catch (SocketException _) {
+        } catch (Exception e) {
+            logger.error("Error receiving packet");
+            throw new ReceiveFailedException("Failed to receive UDP packet", e);
+        }
+
+        return null;
+    }
+
+    @Override
+    public void close() {
+        if (datagramSocket != null && !datagramSocket.isClosed()) {
+            datagramSocket.close();
+        }
+
+        connected = false;
+
+        logger.info("UDP connection closed");
+    }
+
+    @Override
+    public boolean isConnected() {
+        return connected;
+    }
+}
diff --git a/src/main/java/com/han/asd/api/network/discovery/Discovery.java b/src/main/java/com/han/asd/api/network/discovery/Discovery.java
new file mode 100644
index 0000000000000000000000000000000000000000..46863feaec15fe93cc5dfc6a39285f7dfd5fa7fd
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/discovery/Discovery.java
@@ -0,0 +1,13 @@
+package com.han.asd.api.network.discovery;
+
+import com.han.asd.api.network.exceptions.ConnectionFailedException;
+import com.han.asd.api.network.exceptions.SendFailedException;
+import java.util.List;
+
+public interface Discovery {
+    void allowHostDiscovery(int port) throws ConnectionFailedException;
+    void disableHostDiscovery();
+    void discoverHosts(int server_port, int port) throws ConnectionFailedException, SendFailedException;
+    void stopHostDiscovery();
+    List<String> getHosts();
+}
diff --git a/src/main/java/com/han/asd/api/network/discovery/LocalDiscovery.java b/src/main/java/com/han/asd/api/network/discovery/LocalDiscovery.java
new file mode 100644
index 0000000000000000000000000000000000000000..acb5d701322bef0d05c1b7f79ec57d44b91f6f30
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/discovery/LocalDiscovery.java
@@ -0,0 +1,71 @@
+package com.han.asd.api.network.discovery;
+
+import com.han.asd.api.network.connection.UDPConnection;
+import com.han.asd.api.network.exceptions.ConnectionFailedException;
+import com.han.asd.api.network.exceptions.SendFailedException;
+import com.han.asd.api.network.packet.Packet;
+import com.han.asd.api.network.packets.DiscoveryPacket;
+import com.han.asd.api.network.server.BaseUDPServer;
+import com.han.asd.api.network.server.MulticastServer;
+import com.han.asd.api.network.server.UDPServer;
+import com.han.asd.api.network.tick.TickManager;
+import com.han.asd.api.threading.ThreadManager;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public class LocalDiscovery implements Discovery {
+    private BaseUDPServer hostDiscoveryServer;
+    private BaseUDPServer discoverServer;
+    private final ThreadManager threadManager;
+    private final TickManager tickManager;
+    private final InetAddress mcastAddress;
+    private final List<String> hosts;
+
+    public LocalDiscovery(ThreadManager threadManager, TickManager tickManager, InetAddress mcastAddress) {
+        this.threadManager = threadManager;
+        this.tickManager = tickManager;
+        this.mcastAddress = mcastAddress;
+        this.hosts = new CopyOnWriteArrayList<>();
+    }
+
+    @Override
+    public void allowHostDiscovery(int port) throws ConnectionFailedException {
+        hostDiscoveryServer = new MulticastServer(mcastAddress, tickManager);
+        hostDiscoveryServer.start(port);
+        threadManager.runOperation(hostDiscoveryServer);
+    }
+
+    @Override
+    public void disableHostDiscovery() {
+        threadManager.stopOperation(hostDiscoveryServer);
+    }
+
+    @Override
+    public void discoverHosts(int server_port, int port) throws ConnectionFailedException, SendFailedException {
+        try {
+            discoverServer = new UDPServer(tickManager);
+            discoverServer.start(port);
+
+            threadManager.runOperation(discoverServer);
+
+            Packet packet = new DiscoveryPacket(InetAddress.getLocalHost().getHostAddress());
+            UDPConnection udpConnection = new UDPConnection(mcastAddress, server_port);
+            udpConnection.send(packet);
+        } catch (IOException e) {
+            throw new SendFailedException("Failed to send discover packet", e);
+        }
+    }
+
+    @Override
+    public void stopHostDiscovery() {
+        threadManager.stopOperation(discoverServer);
+    }
+
+    @Override
+    public List<String> getHosts() {
+        return hosts;
+    }
+}
diff --git a/src/main/java/com/han/asd/network/listeners/DiscoveryPacketListener.java b/src/main/java/com/han/asd/api/network/discovery/listeners/DiscoveryPacketListener.java
similarity index 54%
rename from src/main/java/com/han/asd/network/listeners/DiscoveryPacketListener.java
rename to src/main/java/com/han/asd/api/network/discovery/listeners/DiscoveryPacketListener.java
index abf8548d51b617da4a16783e296f444077774e2f..5e965ef1b9959761bbec6d929f3b19233035ef77 100644
--- a/src/main/java/com/han/asd/network/listeners/DiscoveryPacketListener.java
+++ b/src/main/java/com/han/asd/api/network/discovery/listeners/DiscoveryPacketListener.java
@@ -1,15 +1,14 @@
-package com.han.asd.network.listeners;
-
-import com.han.asd.Main;
-import com.han.asd.network.Network;
-import com.han.asd.network.connection.UDPConnection;
-import com.han.asd.network.exceptions.SendFailedException;
-import com.han.asd.network.packet.Packet;
-import com.han.asd.network.packet.PacketHandler;
-import com.han.asd.network.packet.PacketListener;
-import com.han.asd.network.packet.PacketPriority;
-import com.han.asd.network.packets.DiscoveryPacket;
-import com.han.asd.network.packets.DiscoveryResponsePacket;
+package com.han.asd.api.network.discovery.listeners;
+
+import com.han.asd.api.network.connection.UDPConnection;
+import com.han.asd.api.network.exceptions.SendFailedException;
+import com.han.asd.api.network.packet.Packet;
+import com.han.asd.api.network.packet.PacketHandler;
+import com.han.asd.api.network.packet.PacketListener;
+import com.han.asd.api.network.packet.PacketPriority;
+import com.han.asd.api.network.packets.DiscoveryPacket;
+import com.han.asd.api.network.packets.DiscoveryResponsePacket;
+import com.han.asd.network.LocalNetwork;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -20,12 +19,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 public class DiscoveryPacketListener implements PacketListener {
     private static final Logger logger = LogManager.getLogger(DiscoveryPacketListener.class);
-    private final Network network;
     private final AtomicBoolean busy;
+    private final LocalNetwork network;
 
-    public DiscoveryPacketListener(Network network) {
-        this.network = network;
+    public DiscoveryPacketListener(LocalNetwork network) {
         this.busy = new AtomicBoolean(false);
+        this.network = network;
     }
 
     @PacketHandler(priority = PacketPriority.MONITOR)
@@ -34,18 +33,14 @@ public class DiscoveryPacketListener implements PacketListener {
             return;
         }
 
-//        String localAddresss = InetAddress.getLocalHost().getHostAddress();
-//        if (discoveryPacket.getSourceAddress().equals(localAddresss))
-//            return;
-
         busy.set(true);
 
-        logger.info("Discovery packet received from: {} {}", discoveryPacket.getSourceAddress(), network.getPort());
+        logger.info("Discovery packet received from: {}", discoveryPacket.getSourceAddress());
 
         InetAddress targetAddress = InetAddress.getByName(discoveryPacket.getSourceAddress());
 
         Packet packet = new DiscoveryResponsePacket(InetAddress.getLocalHost().getHostAddress());
-        UDPConnection udpConnection = new UDPConnection(targetAddress, Main.TEST_DUNGEON_PORT_2);
+        UDPConnection udpConnection = new UDPConnection(targetAddress, network.getDiscoveryServerPort());
         udpConnection.send(packet);
 
         busy.set(false);
diff --git a/src/main/java/com/han/asd/network/listeners/DiscoveryResponsePacketListener.java b/src/main/java/com/han/asd/api/network/discovery/listeners/DiscoveryResponsePacketListener.java
similarity index 51%
rename from src/main/java/com/han/asd/network/listeners/DiscoveryResponsePacketListener.java
rename to src/main/java/com/han/asd/api/network/discovery/listeners/DiscoveryResponsePacketListener.java
index 2da70c74d41555d35d55040104deec97ba4be51c..0409f74391459d21c3b50f1b33c2fca2d3d929cf 100644
--- a/src/main/java/com/han/asd/network/listeners/DiscoveryResponsePacketListener.java
+++ b/src/main/java/com/han/asd/api/network/discovery/listeners/DiscoveryResponsePacketListener.java
@@ -1,24 +1,24 @@
-package com.han.asd.network.listeners;
+package com.han.asd.api.network.discovery.listeners;
 
-import com.han.asd.network.Network;
-import com.han.asd.network.packet.PacketHandler;
-import com.han.asd.network.packet.PacketListener;
-import com.han.asd.network.packet.PacketPriority;
-import com.han.asd.network.packets.DiscoveryResponsePacket;
+import com.han.asd.api.network.packet.PacketHandler;
+import com.han.asd.api.network.packet.PacketListener;
+import com.han.asd.api.network.packet.PacketPriority;
+import com.han.asd.api.network.packets.DiscoveryResponsePacket;
+import com.han.asd.network.LocalNetwork;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
 public class DiscoveryResponsePacketListener implements PacketListener {
     private static final Logger logger = LogManager.getLogger(DiscoveryResponsePacketListener.class);
-    private final Network network;
+    private final LocalNetwork network;
 
-    public DiscoveryResponsePacketListener(Network network) {
+    public DiscoveryResponsePacketListener(LocalNetwork network) {
         this.network = network;
     }
 
     @PacketHandler(priority = PacketPriority.MONITOR)
     public void onDiscoveryResponsePacket(DiscoveryResponsePacket discoveryPacket) {
         logger.info("Discovery response received from: {}", discoveryPacket.getDestinationAddress());
-        network.getHosts().add(discoveryPacket.getDestinationAddress());
+        network.getDiscovery().getHosts().add(discoveryPacket.getDestinationAddress());
     }
 }
diff --git a/src/main/java/com/han/asd/network/exceptions/ConnectionFailedException.java b/src/main/java/com/han/asd/api/network/exceptions/ConnectionFailedException.java
similarity index 83%
rename from src/main/java/com/han/asd/network/exceptions/ConnectionFailedException.java
rename to src/main/java/com/han/asd/api/network/exceptions/ConnectionFailedException.java
index a920bbacbda5f3dc0e3fb51d714b5451bf9df506..bab99c1fce0cdb43dcf8dbb3ab1529a0ba74d3b8 100644
--- a/src/main/java/com/han/asd/network/exceptions/ConnectionFailedException.java
+++ b/src/main/java/com/han/asd/api/network/exceptions/ConnectionFailedException.java
@@ -1,11 +1,11 @@
-package com.han.asd.network.exceptions;
-
-public class ConnectionFailedException extends Exception {
-    public ConnectionFailedException(String message) {
-        super(message);
-    }
-
-    public ConnectionFailedException(String message, Throwable cause) {
-        super(message, cause);
-    }
-}
+package com.han.asd.api.network.exceptions;
+
+public class ConnectionFailedException extends Exception {
+    public ConnectionFailedException(String message) {
+        super(message);
+    }
+
+    public ConnectionFailedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/src/main/java/com/han/asd/network/exceptions/DisconnectFailedException.java b/src/main/java/com/han/asd/api/network/exceptions/DisconnectFailedException.java
similarity index 83%
rename from src/main/java/com/han/asd/network/exceptions/DisconnectFailedException.java
rename to src/main/java/com/han/asd/api/network/exceptions/DisconnectFailedException.java
index 6995bc7106ea9a7a39bc87326c4c0fa170a07a66..a988bb7592119c18e3f177ff4959a87aebe3ba16 100644
--- a/src/main/java/com/han/asd/network/exceptions/DisconnectFailedException.java
+++ b/src/main/java/com/han/asd/api/network/exceptions/DisconnectFailedException.java
@@ -1,11 +1,11 @@
-package com.han.asd.network.exceptions;
-
-public class DisconnectFailedException extends Exception {
-    public DisconnectFailedException(String message) {
-        super(message);
-    }
-
-    public DisconnectFailedException(String message, Throwable cause) {
-        super(message, cause);
-    }
-}
+package com.han.asd.api.network.exceptions;
+
+public class DisconnectFailedException extends Exception {
+    public DisconnectFailedException(String message) {
+        super(message);
+    }
+
+    public DisconnectFailedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/src/main/java/com/han/asd/network/exceptions/DispatchPacketException.java b/src/main/java/com/han/asd/api/network/exceptions/DispatchPacketException.java
similarity index 85%
rename from src/main/java/com/han/asd/network/exceptions/DispatchPacketException.java
rename to src/main/java/com/han/asd/api/network/exceptions/DispatchPacketException.java
index 50f566139e01fff56a00a160f0f69d6332fc0e0b..bc82529a223c83be211a3f9aa08f53aa6d7dafe8 100644
--- a/src/main/java/com/han/asd/network/exceptions/DispatchPacketException.java
+++ b/src/main/java/com/han/asd/api/network/exceptions/DispatchPacketException.java
@@ -1,4 +1,4 @@
-package com.han.asd.network.exceptions;
+package com.han.asd.api.network.exceptions;
 
 public class DispatchPacketException extends Exception {
     public DispatchPacketException(String errorMessage) {
diff --git a/src/main/java/com/han/asd/network/exceptions/NetworkConfigurationException.java b/src/main/java/com/han/asd/api/network/exceptions/NetworkConfigurationException.java
similarity index 84%
rename from src/main/java/com/han/asd/network/exceptions/NetworkConfigurationException.java
rename to src/main/java/com/han/asd/api/network/exceptions/NetworkConfigurationException.java
index 14d2f4e76494c5ccebe9c7c2ac83d427c568ae3c..9b077ed1f9eb04819fcdec7a9a3d84490c45029c 100644
--- a/src/main/java/com/han/asd/network/exceptions/NetworkConfigurationException.java
+++ b/src/main/java/com/han/asd/api/network/exceptions/NetworkConfigurationException.java
@@ -1,11 +1,11 @@
-package com.han.asd.network.exceptions;
-
-public class NetworkConfigurationException extends Exception {
-    public NetworkConfigurationException(String errorMessage) {
-        super(errorMessage);
-    }
-
-    public NetworkConfigurationException(String message, Throwable cause) {
-        super(message, cause);
-    }
+package com.han.asd.api.network.exceptions;
+
+public class NetworkConfigurationException extends Exception {
+    public NetworkConfigurationException(String errorMessage) {
+        super(errorMessage);
+    }
+
+    public NetworkConfigurationException(String message, Throwable cause) {
+        super(message, cause);
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/han/asd/network/exceptions/PacketParsingException.java b/src/main/java/com/han/asd/api/network/exceptions/PacketParsingException.java
similarity index 83%
rename from src/main/java/com/han/asd/network/exceptions/PacketParsingException.java
rename to src/main/java/com/han/asd/api/network/exceptions/PacketParsingException.java
index 28273062e36ea9ae0c1e2d46dd015c77e24fb6cc..01b15bb0f4adfd2418708f36c3759d7d5da80f83 100644
--- a/src/main/java/com/han/asd/network/exceptions/PacketParsingException.java
+++ b/src/main/java/com/han/asd/api/network/exceptions/PacketParsingException.java
@@ -1,11 +1,11 @@
-package com.han.asd.network.exceptions;
-
-public class PacketParsingException extends Exception {
-    public PacketParsingException(String errorMessage) {
-        super(errorMessage);
-    }
-
-    public PacketParsingException(String message, Throwable cause) {
-        super(message, cause);
-    }
+package com.han.asd.api.network.exceptions;
+
+public class PacketParsingException extends Exception {
+    public PacketParsingException(String errorMessage) {
+        super(errorMessage);
+    }
+
+    public PacketParsingException(String message, Throwable cause) {
+        super(message, cause);
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/han/asd/network/exceptions/ReceiveFailedException.java b/src/main/java/com/han/asd/api/network/exceptions/ReceiveFailedException.java
similarity index 83%
rename from src/main/java/com/han/asd/network/exceptions/ReceiveFailedException.java
rename to src/main/java/com/han/asd/api/network/exceptions/ReceiveFailedException.java
index 3f0c3456f44bab2145d56dee39c239b85b32e86c..70f7c87ad992db08c68155f0beadf0460410a1b8 100644
--- a/src/main/java/com/han/asd/network/exceptions/ReceiveFailedException.java
+++ b/src/main/java/com/han/asd/api/network/exceptions/ReceiveFailedException.java
@@ -1,11 +1,11 @@
-package com.han.asd.network.exceptions;
-
-public class ReceiveFailedException extends Exception {
-    public ReceiveFailedException(String errorMessage) {
-        super(errorMessage);
-    }
-
-    public ReceiveFailedException(String message, Throwable cause) {
-        super(message, cause);
-    }
+package com.han.asd.api.network.exceptions;
+
+public class ReceiveFailedException extends Exception {
+    public ReceiveFailedException(String errorMessage) {
+        super(errorMessage);
+    }
+
+    public ReceiveFailedException(String message, Throwable cause) {
+        super(message, cause);
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/han/asd/network/exceptions/SendFailedException.java b/src/main/java/com/han/asd/api/network/exceptions/SendFailedException.java
similarity index 83%
rename from src/main/java/com/han/asd/network/exceptions/SendFailedException.java
rename to src/main/java/com/han/asd/api/network/exceptions/SendFailedException.java
index 1675d284554675973a55fba794a6e15b31055755..ce6076abffa3a1eb84c1478b824067398ba554fe 100644
--- a/src/main/java/com/han/asd/network/exceptions/SendFailedException.java
+++ b/src/main/java/com/han/asd/api/network/exceptions/SendFailedException.java
@@ -1,11 +1,11 @@
-package com.han.asd.network.exceptions;
-
-public class SendFailedException extends Exception {
-    public SendFailedException(String errorMessage) {
-        super(errorMessage);
-    }
-
-    public SendFailedException(String message, Throwable cause) {
-        super(message, cause);
-    }
+package com.han.asd.api.network.exceptions;
+
+public class SendFailedException extends Exception {
+    public SendFailedException(String errorMessage) {
+        super(errorMessage);
+    }
+
+    public SendFailedException(String message, Throwable cause) {
+        super(message, cause);
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/han/asd/network/packet/Packet.java b/src/main/java/com/han/asd/api/network/packet/Packet.java
similarity index 61%
rename from src/main/java/com/han/asd/network/packet/Packet.java
rename to src/main/java/com/han/asd/api/network/packet/Packet.java
index 22b65374a2ad35395ebf4a88135737a0a1a5c02a..0415a5f413a0e9d25953bd9a9a786a6632444373 100644
--- a/src/main/java/com/han/asd/network/packet/Packet.java
+++ b/src/main/java/com/han/asd/api/network/packet/Packet.java
@@ -1,23 +1,17 @@
-package com.han.asd.network.packet;
+package com.han.asd.api.network.packet;
 
 import java.util.UUID;
 
 public abstract class Packet {
     private final long timestamp;
 
-    private static final UUID uuid = UUID.randomUUID();
     public Packet() {
         this.timestamp = System.currentTimeMillis();
     }
 
-
     public long getTimestamp() {
         return timestamp;
     }
-
-    public UUID getUuid() {
-        return uuid;
-    }
 }
 
 
diff --git a/src/main/java/com/han/asd/network/packet/PacketDispatcher.java b/src/main/java/com/han/asd/api/network/packet/PacketDispatcher.java
similarity index 96%
rename from src/main/java/com/han/asd/network/packet/PacketDispatcher.java
rename to src/main/java/com/han/asd/api/network/packet/PacketDispatcher.java
index f5c5e45f4dca1d1d90b8e2c0508868a8b7b554e2..2d5b78427689c1bd0e9c0ccacb274c586daaadbc 100644
--- a/src/main/java/com/han/asd/network/packet/PacketDispatcher.java
+++ b/src/main/java/com/han/asd/api/network/packet/PacketDispatcher.java
@@ -1,6 +1,6 @@
-package com.han.asd.network.packet;
+package com.han.asd.api.network.packet;
 
-import com.han.asd.network.exceptions.DispatchPacketException;
+import com.han.asd.api.network.exceptions.DispatchPacketException;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
diff --git a/src/main/java/com/han/asd/network/packet/PacketHandler.java b/src/main/java/com/han/asd/api/network/packet/PacketHandler.java
similarity index 89%
rename from src/main/java/com/han/asd/network/packet/PacketHandler.java
rename to src/main/java/com/han/asd/api/network/packet/PacketHandler.java
index 686513a66243da6c248372e6004587b351eaa444..9dee0a3a54fb260be5dc4da73230559dceeaeba0 100644
--- a/src/main/java/com/han/asd/network/packet/PacketHandler.java
+++ b/src/main/java/com/han/asd/api/network/packet/PacketHandler.java
@@ -1,4 +1,4 @@
-package com.han.asd.network.packet;
+package com.han.asd.api.network.packet;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
diff --git a/src/main/java/com/han/asd/api/network/packet/PacketListener.java b/src/main/java/com/han/asd/api/network/packet/PacketListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b29223f3b57b741a98c44b82277c9e70b1c2d46
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/packet/PacketListener.java
@@ -0,0 +1,4 @@
+package com.han.asd.api.network.packet;
+
+public interface PacketListener {
+}
\ No newline at end of file
diff --git a/src/main/java/com/han/asd/network/packet/PacketListenerPriorityComparator.java b/src/main/java/com/han/asd/api/network/packet/PacketListenerPriorityComparator.java
similarity index 69%
rename from src/main/java/com/han/asd/network/packet/PacketListenerPriorityComparator.java
rename to src/main/java/com/han/asd/api/network/packet/PacketListenerPriorityComparator.java
index 03d97961b50a12b95e91774f9ff80a1ec80f34d0..4804aea99f42810cda0c697a97c421014c2fe41c 100644
--- a/src/main/java/com/han/asd/network/packet/PacketListenerPriorityComparator.java
+++ b/src/main/java/com/han/asd/api/network/packet/PacketListenerPriorityComparator.java
@@ -1,4 +1,4 @@
-package com.han.asd.network.packet;
+package com.han.asd.api.network.packet;
 
 import java.lang.reflect.Method;
 import java.util.Comparator;
@@ -6,6 +6,6 @@ import java.util.Comparator;
 public class PacketListenerPriorityComparator implements Comparator<Method> {
     @Override
     public int compare(Method one, Method two) {
-        return one.getAnnotation(PacketHandler.class).priority().getSlot() - two.getAnnotation(PacketHandler.class).priority().getSlot();
+        return one.getAnnotation(PacketHandler.class).priority().getPriority() - two.getAnnotation(PacketHandler.class).priority().getPriority();
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/han/asd/api/network/packet/PacketPriority.java b/src/main/java/com/han/asd/api/network/packet/PacketPriority.java
new file mode 100644
index 0000000000000000000000000000000000000000..c0fa755a04c1685fbf4932665116f128f643df3f
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/packet/PacketPriority.java
@@ -0,0 +1,20 @@
+package com.han.asd.api.network.packet;
+
+public enum PacketPriority {
+    LOWEST(0),
+    LOW(1),
+    NORMAL(2),
+    HIGH(3),
+    HIGHEST(4),
+    MONITOR(5);
+
+    private final int priority;
+
+    PacketPriority(int priority) {
+        this.priority = priority;
+    }
+
+    public int getPriority() {
+        return priority;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/han/asd/network/packets/DiscoveryPacket.java b/src/main/java/com/han/asd/api/network/packets/DiscoveryPacket.java
similarity index 75%
rename from src/main/java/com/han/asd/network/packets/DiscoveryPacket.java
rename to src/main/java/com/han/asd/api/network/packets/DiscoveryPacket.java
index aa092e81de64747d45e46c2afcbf482eae290aca..26b28dd8ec236df0a51a7088419769910f42d773 100644
--- a/src/main/java/com/han/asd/network/packets/DiscoveryPacket.java
+++ b/src/main/java/com/han/asd/api/network/packets/DiscoveryPacket.java
@@ -1,6 +1,6 @@
-package com.han.asd.network.packets;
+package com.han.asd.api.network.packets;
 
-import com.han.asd.network.packet.Packet;
+import com.han.asd.api.network.packet.Packet;
 
 public class DiscoveryPacket extends Packet {
     private final String sourceAddress;
diff --git a/src/main/java/com/han/asd/network/packets/DiscoveryResponsePacket.java b/src/main/java/com/han/asd/api/network/packets/DiscoveryResponsePacket.java
similarity index 78%
rename from src/main/java/com/han/asd/network/packets/DiscoveryResponsePacket.java
rename to src/main/java/com/han/asd/api/network/packets/DiscoveryResponsePacket.java
index 315f4aee935e7d8680cadbf9fb710b6fad82240a..875b8359a112e71306d29265bcd659e76aa2d71b 100644
--- a/src/main/java/com/han/asd/network/packets/DiscoveryResponsePacket.java
+++ b/src/main/java/com/han/asd/api/network/packets/DiscoveryResponsePacket.java
@@ -1,6 +1,6 @@
-package com.han.asd.network.packets;
+package com.han.asd.api.network.packets;
 
-import com.han.asd.network.packet.Packet;
+import com.han.asd.api.network.packet.Packet;
 
 public class DiscoveryResponsePacket extends Packet {
     private final String destinationAddress;
diff --git a/src/main/java/com/han/asd/api/network/packets/TimeSyncPacket.java b/src/main/java/com/han/asd/api/network/packets/TimeSyncPacket.java
new file mode 100644
index 0000000000000000000000000000000000000000..ef4082b3d1153b16202f32bf5081131d6063f1e1
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/packets/TimeSyncPacket.java
@@ -0,0 +1,10 @@
+package com.han.asd.api.network.packets;
+
+import com.han.asd.api.network.packet.Packet;
+
+public class TimeSyncPacket extends Packet {
+
+    public TimeSyncPacket() {
+
+    }
+}
diff --git a/src/main/java/com/han/asd/api/network/server/BaseUDPServer.java b/src/main/java/com/han/asd/api/network/server/BaseUDPServer.java
new file mode 100644
index 0000000000000000000000000000000000000000..9b3544004fc7360588187d77df70512d52ea824b
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/server/BaseUDPServer.java
@@ -0,0 +1,51 @@
+package com.han.asd.api.network.server;
+
+import com.han.asd.api.network.connection.Connection;
+import com.han.asd.api.network.connection.ConnectionHandler;
+import com.han.asd.api.network.connection.UDPConnection;
+import com.han.asd.api.network.exceptions.ConnectionFailedException;
+import com.han.asd.api.network.tick.TickManager;
+
+import java.net.DatagramSocket;
+
+public abstract class BaseUDPServer implements Server {
+    private final TickManager tickManager;
+    private ConnectionHandler connectionHandler;
+
+    public BaseUDPServer(TickManager tickManager) {
+        this.tickManager = tickManager;
+    }
+
+    public void start(DatagramSocket datagramSocket) {
+        UDPConnection udpConnection = new UDPConnection(datagramSocket);
+        connectionHandler = new ConnectionHandler(tickManager, udpConnection);
+    }
+
+    @Override
+    public abstract void start(int port) throws ConnectionFailedException;
+
+    @Override
+    public void stop() {
+        connectionHandler.stop();
+    }
+
+    @Override
+    public void execute() {
+        connectionHandler.execute();
+    }
+
+    @Override
+    public long getTimeout() {
+        return 1;
+    }
+
+    @Override
+    public int getPriority() {
+        return 0;
+    }
+
+    @Override
+    public Connection getConnection() {
+        return connectionHandler.getConnection();
+    }
+}
diff --git a/src/main/java/com/han/asd/network/server/MulticastServer.java b/src/main/java/com/han/asd/api/network/server/MulticastServer.java
similarity index 52%
rename from src/main/java/com/han/asd/network/server/MulticastServer.java
rename to src/main/java/com/han/asd/api/network/server/MulticastServer.java
index f34d2a2fc1f5d60170e29b84192dd13eef602605..dfa4567a8037388440b7528cb13c75408175ccbf 100644
--- a/src/main/java/com/han/asd/network/server/MulticastServer.java
+++ b/src/main/java/com/han/asd/api/network/server/MulticastServer.java
@@ -1,7 +1,9 @@
-package com.han.asd.network.server;
+package com.han.asd.api.network.server;
 
-import com.han.asd.network.packet.PacketDispatcher;
+import com.han.asd.api.network.exceptions.ConnectionFailedException;
+import com.han.asd.api.network.tick.TickManager;
 
+import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.MulticastSocket;
@@ -11,20 +13,20 @@ public class MulticastServer extends BaseUDPServer {
 
     private final String mcastAddr;
 
-    public MulticastServer(InetAddress mcastAddr, PacketDispatcher packetDispatcher) {
-        super(packetDispatcher);
+    public MulticastServer(InetAddress mcastAddr, TickManager tickManager) {
+        super(tickManager);
         this.mcastAddr = mcastAddr.getHostAddress();
     }
 
     @Override
-    public void start(int port) {
+    public void start(int port) throws ConnectionFailedException {
         try {
             MulticastSocket multicastSocket = new MulticastSocket(port);
             InetAddress group = InetAddress.getByName(mcastAddr);
             multicastSocket.joinGroup(new InetSocketAddress(group, 0), NetworkInterface.getByIndex(0));
-            start(port, multicastSocket);
-        } catch (Exception e) {
-            System.out.println("fout");
+            start(multicastSocket);
+        } catch (IOException e) {
+            throw new ConnectionFailedException("Failed to start multicast server", e);
         }
     }
 }
diff --git a/src/main/java/com/han/asd/api/network/server/Server.java b/src/main/java/com/han/asd/api/network/server/Server.java
new file mode 100644
index 0000000000000000000000000000000000000000..e1ca59aeb8a8ef846bfea38771345f30aa08f54d
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/server/Server.java
@@ -0,0 +1,11 @@
+package com.han.asd.api.network.server;
+
+import com.han.asd.api.network.connection.Connection;
+import com.han.asd.api.network.exceptions.ConnectionFailedException;
+import com.han.asd.api.threading.operation.Operation;
+
+public interface Server extends Operation {
+    void start(int port) throws ConnectionFailedException;
+    void stop();
+    Connection getConnection();
+}
diff --git a/src/main/java/com/han/asd/network/server/TCPServer.java b/src/main/java/com/han/asd/api/network/server/TCPServer.java
similarity index 50%
rename from src/main/java/com/han/asd/network/server/TCPServer.java
rename to src/main/java/com/han/asd/api/network/server/TCPServer.java
index 618ddc15a81d4c6ce570c8d2997065f2f3e85e85..9c0dd7370f934be25faeabc378f7bfafdb59c0ff 100644
--- a/src/main/java/com/han/asd/network/server/TCPServer.java
+++ b/src/main/java/com/han/asd/api/network/server/TCPServer.java
@@ -1,10 +1,11 @@
-package com.han.asd.network.server;
+package com.han.asd.api.network.server;
 
-import com.han.asd.network.connection.ConnectionHandler;
-import com.han.asd.network.connection.TCPConnection;
-import com.han.asd.network.exceptions.ConnectionFailedException;
-import com.han.asd.network.packet.PacketDispatcher;
-import com.han.asd.network.tick.TickManager;
+import com.han.asd.api.network.connection.Connection;
+import com.han.asd.api.network.connection.ConnectionHandler;
+import com.han.asd.api.network.connection.TCPConnection;
+import com.han.asd.api.network.exceptions.ConnectionFailedException;
+import com.han.asd.api.network.tick.TickManager;
+import com.han.asd.api.threading.ThreadManager;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -14,32 +15,32 @@ import java.net.Socket;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
-public class TCPServer implements Server, Runnable {
+public class TCPServer implements Server {
     private static final Logger logger = LogManager.getLogger(TCPServer.class);
-    private final List<ConnectionHandler> connections = new CopyOnWriteArrayList<>();
+    private final List<ConnectionHandler> connectionHandlers = new CopyOnWriteArrayList<>();
     private final TickManager tickManager;
     private ServerSocket serverSocket;
+    private ThreadManager threadManager;
 
-    public TCPServer(TickManager tickManager) {
+    public TCPServer(ThreadManager threadManager, TickManager tickManager) {
         this.tickManager = tickManager;
+        this.threadManager = threadManager;
     }
 
     @Override
     public void start(int port) throws ConnectionFailedException {
         try {
             this.serverSocket = new ServerSocket(port);
-            new Thread(this).start();
-            logger.info("TCP server started on port: {}", port);
         } catch (IOException e) {
-            throw new ConnectionFailedException("TCP server failed to start on port: " + port, e);
+            throw new ConnectionFailedException("Failed to start TCP server");
         }
     }
 
     @Override
     public void stop() {
         try {
-            for (ConnectionHandler connection : connections) {
-                connection.close();
+            for (ConnectionHandler connectionHandler : connectionHandlers) {
+                connectionHandler.stop();
             }
 
             if (!serverSocket.isClosed()) {
@@ -52,25 +53,40 @@ public class TCPServer implements Server, Runnable {
     }
 
     @Override
-    public void run() {
+    public Connection getConnection() {
+        return null;
+    }
+
+    public List<ConnectionHandler> getConnections() {
+        return connectionHandlers;
+    }
+
+    @Override
+    public void execute() {
         try {
-            while (!serverSocket.isClosed()) {
+            while (!Thread.interrupted() && !serverSocket.isClosed()) {
                 Socket socket = serverSocket.accept();
                 TCPConnection clientConnection = new TCPConnection(socket);
 
                 if (clientConnection.isConnected()) {
-                    ConnectionHandler connectionHandler = new ConnectionHandler(tickManager);
-                    connectionHandler.start(clientConnection);
-                    connections.add(connectionHandler);
+                    ConnectionHandler connectionHandler = new ConnectionHandler(tickManager, clientConnection);
+                    connectionHandlers.add(connectionHandler);
+                    threadManager.runOperation(connectionHandler);
                     logger.info("New TCP connection established");
                 }
             }
-        } catch (IOException e) {
+        } catch (IOException | ConnectionFailedException e) {
             logger.info("TCP server socket closed");
         }
     }
 
-    public List<ConnectionHandler> getConnections() {
-        return connections;
+    @Override
+    public long getTimeout() {
+        return 1;
+    }
+
+    @Override
+    public int getPriority() {
+        return 0;
     }
 }
diff --git a/src/main/java/com/han/asd/api/network/server/UDPServer.java b/src/main/java/com/han/asd/api/network/server/UDPServer.java
new file mode 100644
index 0000000000000000000000000000000000000000..d656c5d38ed0d9f29099b503e3c6c576b4bf3925
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/server/UDPServer.java
@@ -0,0 +1,26 @@
+package com.han.asd.api.network.server;
+
+import com.han.asd.api.network.exceptions.ConnectionFailedException;
+import com.han.asd.api.network.tick.TickManager;
+
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+
+public class UDPServer extends BaseUDPServer {
+
+    public UDPServer(TickManager tickManager) {
+        super(tickManager);
+    }
+
+    @Override
+    public void start(int port) throws ConnectionFailedException {
+        try {
+            DatagramSocket datagramSocket = new DatagramSocket(port, InetAddress.getLocalHost());
+            start(datagramSocket);
+        } catch (UnknownHostException | SocketException e) {
+            throw new ConnectionFailedException("Failed to start UDP server", e);
+        }
+    }
+}
diff --git a/src/main/java/com/han/asd/api/network/tick/Tick.java b/src/main/java/com/han/asd/api/network/tick/Tick.java
new file mode 100644
index 0000000000000000000000000000000000000000..9f0cc805ad92691e5962824da5873f567d902e13
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/tick/Tick.java
@@ -0,0 +1,29 @@
+package com.han.asd.api.network.tick;
+
+public class Tick {
+
+    private long delta;
+
+    public Tick(long delta) {
+        this.delta = delta;
+    }
+
+    public long millisToNextSecond() {
+        long synchronizedSystemTime = System.currentTimeMillis() + this.delta;
+        return 1000 - (synchronizedSystemTime % 1000);
+    }
+
+    public long calculateDelta(long clientTime) {
+        long serverTime = System.currentTimeMillis();
+        long latency = (serverTime - clientTime) / 2;
+        return (serverTime - clientTime) + latency;
+    }
+
+    public long getDelta() {
+        return delta;
+    }
+
+    public void setDelta(long delta) {
+        this.delta = delta;
+    }
+}
diff --git a/src/main/java/com/han/asd/api/network/tick/TickManager.java b/src/main/java/com/han/asd/api/network/tick/TickManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..29a54f2c55bbb08ae1e1ce9dba74c0bab83905a3
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/tick/TickManager.java
@@ -0,0 +1,76 @@
+package com.han.asd.api.network.tick;
+
+import com.han.asd.api.network.exceptions.DispatchPacketException;
+import com.han.asd.api.network.packet.Packet;
+import com.han.asd.api.network.packet.PacketDispatcher;
+import com.han.asd.api.threading.operation.Operation;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class TickManager implements Operation {
+    private static final Logger logger = LogManager.getLogger(TickManager.class);
+    private final Tick tick;
+    private final Queue<Packet> queue;
+    private final PacketDispatcher packetDispatcher;
+    private final int tickCount;
+    private final AtomicBoolean sync;
+
+    public TickManager(PacketDispatcher packetDispatcher, int tickCount) {
+        this.tick = new Tick(0);
+        this.queue = new LinkedList<>();
+        this.packetDispatcher = packetDispatcher;
+        this.tickCount = tickCount;
+        this.sync = new AtomicBoolean(false);
+    }
+
+    public void sync() {
+        sync.set(true);
+    }
+
+    public Queue<Packet> getQueue() {
+        return queue;
+    }
+
+    @Override
+    public void execute() {
+        try {
+            while(!Thread.interrupted()) {
+                if (sync.get()) {
+                    Thread.sleep(tick.millisToNextSecond());
+                    sync.set(false);
+                }
+
+                Packet packet = queue.poll();
+                if (packet == null)
+                    continue;
+
+                tick.setDelta(tick.calculateDelta(packet.getTimestamp()));
+
+                packetDispatcher.dispatch(packet);
+
+                Thread.sleep(1000 / tickCount);
+            }
+        } catch (InterruptedException | DispatchPacketException e) {
+            logger.error("Error dispatching TickManager queue: ", e);
+        }
+    }
+
+    @Override
+    public long getTimeout() {
+        return 1;
+    }
+
+    @Override
+    public int getPriority() {
+        return 0;
+    }
+
+    @Override
+    public void stop() {
+
+    }
+}
diff --git a/src/main/java/com/han/asd/api/network/tick/listeners/TimeSyncPacketListener.java b/src/main/java/com/han/asd/api/network/tick/listeners/TimeSyncPacketListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..223b62e31ca831933c5d50cbfe5b8bb29b2859b3
--- /dev/null
+++ b/src/main/java/com/han/asd/api/network/tick/listeners/TimeSyncPacketListener.java
@@ -0,0 +1,24 @@
+package com.han.asd.api.network.tick.listeners;
+
+import com.han.asd.api.network.packet.PacketHandler;
+import com.han.asd.api.network.packet.PacketListener;
+import com.han.asd.api.network.packet.PacketPriority;
+import com.han.asd.api.network.packets.TimeSyncPacket;
+import com.han.asd.network.LocalNetwork;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class TimeSyncPacketListener implements PacketListener {
+    private static final Logger logger = LogManager.getLogger(TimeSyncPacketListener.class);
+    private final LocalNetwork network;
+
+    public TimeSyncPacketListener(LocalNetwork network) {
+        this.network = network;
+    }
+
+    @PacketHandler(priority = PacketPriority.MONITOR)
+    public void onTimeSync(TimeSyncPacket timeSyncPacket) {
+        logger.info("Time sync packet received");
+        network.getTickManager().sync();
+    }
+}
diff --git a/src/main/java/com/han/asd/api/threading/ComparableFutureTask.java b/src/main/java/com/han/asd/api/threading/ComparableFutureTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..6bc79cf70919acb237b2fccba62f089fc02099de
--- /dev/null
+++ b/src/main/java/com/han/asd/api/threading/ComparableFutureTask.java
@@ -0,0 +1,17 @@
+package com.han.asd.api.threading;
+
+import java.util.concurrent.FutureTask;
+
+public class ComparableFutureTask<V> extends FutureTask<V> implements Comparable<ComparableFutureTask<V>> {
+    private final int priority;
+
+    public ComparableFutureTask(Runnable runnable, V result, int priority) {
+        super(runnable, result);
+        this.priority = priority;
+    }
+
+    @Override
+    public int compareTo(ComparableFutureTask<V> o) {
+        return Integer.compare(priority, o.priority);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/han/asd/api/threading/PriorityRunnable.java b/src/main/java/com/han/asd/api/threading/PriorityRunnable.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5b929fbb74b87bfc9cfa19332d4ef893831e019
--- /dev/null
+++ b/src/main/java/com/han/asd/api/threading/PriorityRunnable.java
@@ -0,0 +1,25 @@
+package com.han.asd.api.threading;
+
+public class PriorityRunnable implements Runnable, Comparable<PriorityRunnable> {
+    private final int priority;
+    private final Runnable task;
+
+    public PriorityRunnable(int priority, Runnable task) {
+        this.priority = priority;
+        this.task = task;
+    }
+
+    @Override
+    public void run() {
+        task.run();
+    }
+
+    @Override
+    public int compareTo(PriorityRunnable o) {
+        return Integer.compare(priority, o.priority);
+    }
+
+    public int getPriority() {
+        return priority;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/han/asd/api/threading/ThreadManager.java b/src/main/java/com/han/asd/api/threading/ThreadManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..63598c3ea50f2677fa7ba686ea9bf4e8752078f8
--- /dev/null
+++ b/src/main/java/com/han/asd/api/threading/ThreadManager.java
@@ -0,0 +1,81 @@
+package com.han.asd.api.threading;
+
+import com.han.asd.api.threading.operation.Operation;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Manages a thread pool and executes operations on it.
+ */
+public class ThreadManager {
+    private static final Logger logger = LogManager.getLogger(ThreadManager.class);
+
+    private final ExecutorService executorService;
+    private final Map<Operation, Thread> threads;
+
+    /**
+     * Creates a new thread manager with the specified number of threads.
+     *
+     * @param numberOfThreads The number of threads to create.
+     */
+    public ThreadManager(int numberOfThreads) {
+        this.threads = new HashMap<>();
+        this.executorService = Executors.newFixedThreadPool(numberOfThreads);
+    }
+
+    /**
+     * Executes the specified operation on the thread pool.
+     *
+     * @param operation The operation to execute.
+     */
+    public void runOperation(Operation operation) {
+        executorService.execute(() -> {
+            Thread t = Thread.currentThread();
+            try {
+                logger.info("Executing operation on: " + t.getName());
+                threads.put(operation, t);
+                operation.execute();
+            } catch (Exception e) {
+                logger.info("An exception occurred in thread " + t.getName(), e);
+            }
+        });
+    }
+
+    /**
+     * Interrupts the specified operation on the thread pool.
+     *
+     * @param operation The operation to interrupt.
+     */
+    public void stopOperation(Operation operation) {
+        Thread thread = threads.get(operation);
+        if (thread != null) {
+            thread.interrupt();
+            threads.remove(operation, thread);
+            operation.stop();
+        }
+    }
+
+    /**
+     * Shuts down the thread pool.
+     */
+    public void shutdown() {
+        executorService.shutdown();
+        try {
+            // Wait a while for existing tasks to terminate.
+            if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
+                executorService.shutdownNow();
+                // Wait a while for tasks to respond to being canceled.
+                if (!executorService.awaitTermination(60, TimeUnit.SECONDS))
+                    logger.error("Pool did not terminate");
+            }
+        } catch (InterruptedException ie) {
+            executorService.shutdownNow();
+            Thread.currentThread().interrupt();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/han/asd/api/threading/operation/Operation.java b/src/main/java/com/han/asd/api/threading/operation/Operation.java
new file mode 100644
index 0000000000000000000000000000000000000000..155b4876f4e1cf9372e5456ab1d143898d35c146
--- /dev/null
+++ b/src/main/java/com/han/asd/api/threading/operation/Operation.java
@@ -0,0 +1,11 @@
+package com.han.asd.api.threading.operation;
+
+public interface Operation {
+    void execute();
+
+    long getTimeout();
+
+    int getPriority();
+
+    void stop();
+}
\ No newline at end of file
diff --git a/src/main/java/com/han/asd/game/DungeonGame.java b/src/main/java/com/han/asd/game/DungeonGame.java
new file mode 100644
index 0000000000000000000000000000000000000000..230058bc93c7b36ecad15558ce194e4dc536285e
--- /dev/null
+++ b/src/main/java/com/han/asd/game/DungeonGame.java
@@ -0,0 +1,54 @@
+package com.han.asd.game;
+
+import com.han.asd.api.network.exceptions.ConnectionFailedException;
+import com.han.asd.api.network.exceptions.DisconnectFailedException;
+import com.han.asd.listener.ConnectionPacketListener;
+import com.han.asd.listener.DisconnectPacketListener;
+import com.han.asd.network.LocalNetwork;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+
+public class DungeonGame {
+    private static final Logger logger = LogManager.getLogger(DungeonGame.class);
+    private final LocalNetwork network;
+
+    public DungeonGame() throws UnknownHostException {
+        this.network = new LocalNetwork();
+    }
+
+    public void createGame() throws ConnectionFailedException {
+        network.startHost();
+
+        network.getPacketDispatcher().register(new ConnectionPacketListener());
+        network.getPacketDispatcher().register(new DisconnectPacketListener());
+
+        logger.info("Lobby created and started");
+    }
+
+    public void stopGame() {
+        network.stopHost();
+        logger.info("Lobby stopped");
+    }
+
+    public void discoverGames(int timeout) {
+        logger.info("Started discovery to join lobby");
+        network.discoverHosts(timeout);
+    }
+
+    public void joinGame(String ip) throws ConnectionFailedException {
+        logger.info("Trying to join lobby {}", ip);
+        network.connectHost(ip);
+    }
+
+    public void leaveGame() throws DisconnectFailedException {
+        network.disconnectHost();
+        logger.info("Left the lobby");
+    }
+
+    public LocalNetwork getNetwork() {
+        return network;
+    }
+}
diff --git a/src/main/java/com/han/asd/listener/ConnectionPacketListener.java b/src/main/java/com/han/asd/listener/ConnectionPacketListener.java
index 5a45443873221fa34ef3befd61c1890a7f6ef189..c273af7ddca1c38d963c4058b592ee8f635b1144 100644
--- a/src/main/java/com/han/asd/listener/ConnectionPacketListener.java
+++ b/src/main/java/com/han/asd/listener/ConnectionPacketListener.java
@@ -1,8 +1,8 @@
 package com.han.asd.listener;
 
-import com.han.asd.network.packet.PacketHandler;
-import com.han.asd.network.packet.PacketListener;
-import com.han.asd.network.packets.ConnectionPacket;
+import com.han.asd.api.network.packet.PacketHandler;
+import com.han.asd.api.network.packet.PacketListener;
+import com.han.asd.packets.ConnectionPacket;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
diff --git a/src/main/java/com/han/asd/listener/DisconnectPacketListener.java b/src/main/java/com/han/asd/listener/DisconnectPacketListener.java
index fe00307ec8a393e3cc3691b0c1f5a5bf015b76e3..bbefe3e5380f004686285c1beedd16cafb7e1bab 100644
--- a/src/main/java/com/han/asd/listener/DisconnectPacketListener.java
+++ b/src/main/java/com/han/asd/listener/DisconnectPacketListener.java
@@ -1,8 +1,8 @@
 package com.han.asd.listener;
 
-import com.han.asd.network.packet.PacketHandler;
-import com.han.asd.network.packet.PacketListener;
-import com.han.asd.network.packets.DisconnectPacket;
+import com.han.asd.api.network.packet.PacketHandler;
+import com.han.asd.api.network.packet.PacketListener;
+import com.han.asd.packets.DisconnectPacket;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
diff --git a/src/main/java/com/han/asd/network/LocalNetwork.java b/src/main/java/com/han/asd/network/LocalNetwork.java
new file mode 100644
index 0000000000000000000000000000000000000000..e9dfbcdc077f56798fa3cc0a6ba99eb99550fdbd
--- /dev/null
+++ b/src/main/java/com/han/asd/network/LocalNetwork.java
@@ -0,0 +1,176 @@
+package com.han.asd.network;
+
+import com.han.asd.api.network.HostNetwork;
+import com.han.asd.api.network.Network;
+import com.han.asd.api.network.connection.ConnectionHandler;
+import com.han.asd.api.network.connection.TCPConnection;
+import com.han.asd.api.network.discovery.Discovery;
+import com.han.asd.api.network.discovery.LocalDiscovery;
+import com.han.asd.api.network.exceptions.ConnectionFailedException;
+import com.han.asd.api.network.exceptions.DisconnectFailedException;
+import com.han.asd.api.network.exceptions.SendFailedException;
+import com.han.asd.api.network.discovery.listeners.DiscoveryPacketListener;
+import com.han.asd.api.network.discovery.listeners.DiscoveryResponsePacketListener;
+import com.han.asd.api.network.packets.TimeSyncPacket;
+import com.han.asd.api.network.tick.listeners.TimeSyncPacketListener;
+import com.han.asd.api.network.packet.Packet;
+import com.han.asd.api.network.packet.PacketDispatcher;
+import com.han.asd.packets.ConnectionPacket;
+import com.han.asd.packets.DisconnectPacket;
+import com.han.asd.api.network.tick.TickManager;
+import com.han.asd.api.threading.ThreadManager;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+public class LocalNetwork implements Network {
+    private static final Logger logger = LogManager.getLogger(LocalNetwork.class);
+    private final HostNetwork hostNetwork;
+    private final PacketDispatcher packetDispatcher;
+    private final TickManager tickManager;
+    private final ThreadManager threadManager;
+    private ConnectionHandler connectionHandler;
+    private final Discovery discovery;
+
+    public LocalNetwork() throws UnknownHostException {
+        this.packetDispatcher = new PacketDispatcher();
+
+        packetDispatcher.register(new DiscoveryPacketListener(this));
+        packetDispatcher.register(new DiscoveryResponsePacketListener(this));
+        packetDispatcher.register(new TimeSyncPacketListener(this));
+
+        this.tickManager = new TickManager(packetDispatcher, getTickCount());
+        this.threadManager = new ThreadManager(10);
+        threadManager.runOperation(tickManager);
+
+        this.hostNetwork = new HostNetwork(tickManager, threadManager);
+        this.discovery = new LocalDiscovery(threadManager, tickManager, InetAddress.getByName(getDiscoveryAddress()));
+
+        logger.info("Network initialized");
+    }
+
+    @Override
+    public void startHost() throws ConnectionFailedException {
+        int serverPort = getDiscoveryServerPort();
+        discovery.allowHostDiscovery(serverPort);
+        logger.info("Discovery server started on port: {}", serverPort);
+        hostNetwork.startHost(serverPort);
+        logger.info("Lobby server started on port: {}", serverPort);
+    }
+
+    @Override
+    public void stopHost() {
+        discovery.disableHostDiscovery();
+        hostNetwork.stopHost();
+        logger.info("Lobby stopped");
+    }
+
+    public void discoverHosts(int timeout) {
+        try {
+            discovery.discoverHosts(getDiscoveryServerPort(), getDiscoveryClientPort());
+            Thread.sleep(timeout);
+            discovery.stopHostDiscovery();
+            logger.info("Discovered hosts");
+        } catch(SendFailedException | ConnectionFailedException e) {
+            logger.info("Discovery failed");
+        } catch (InterruptedException _) {
+        }
+    }
+
+    @Override
+    public void connectHost(String address) throws ConnectionFailedException {
+        try {
+            Socket socket = new Socket(address, getDiscoveryServerPort());
+            if(socket.isConnected()) {
+                TCPConnection tcpConnection = new TCPConnection(socket);
+
+                if (tcpConnection.isConnected()) {
+                    connectionHandler = new ConnectionHandler(tickManager, tcpConnection);
+                    threadManager.runOperation(connectionHandler);
+
+                    Packet connectionPacket = new ConnectionPacket("test");
+                    connectionHandler.getConnection().send(connectionPacket);
+
+                    Packet timePacket = new TimeSyncPacket();
+                    connectionHandler.getConnection().send(timePacket);
+
+                    logger.info("Connected to lobby at {}", address);
+                }
+            }
+        } catch (Exception e) {
+            logger.error("Couldn't connect to the specified lobby", e);
+            throw new ConnectionFailedException("Failed to connect to " + address, e);
+        }
+    }
+
+    @Override
+    public void disconnectHost() throws DisconnectFailedException {
+        if (connectionHandler.getConnection() == null) {
+            logger.error("Error disconnecting from lobby");
+            return;
+        }
+
+        try {
+            Packet packet = new DisconnectPacket("test");
+            connectionHandler.getConnection().send(packet);
+
+            if (connectionHandler.getConnection().isConnected()) {
+                threadManager.stopOperation(connectionHandler);
+                logger.info("Disconnected from lobby");
+            }
+        } catch (SendFailedException e) {
+            logger.error("Error disconnecting from lobby", e);
+            throw new DisconnectFailedException("Couldn't disconnect from the specified lobby", e);
+        }
+    }
+
+    public Discovery getDiscovery() {
+        return discovery;
+    }
+
+    @Override
+    public int getDiscoveryServerPort() {
+        return 8886;
+    }
+
+    @Override
+    public int getDiscoveryClientPort() {
+        return 8887;
+    }
+
+    @Override
+    public String getDiscoveryAddress() {
+        return "224.0.0.1";
+    }
+
+    @Override
+    public int getTickCount() {
+        return 20;
+    }
+
+    @Override
+    public HostNetwork getHostNetwork() {
+        return hostNetwork;
+    }
+
+    public PacketDispatcher getPacketDispatcher() {
+        return packetDispatcher;
+    }
+
+    public TickManager getTickManager() {
+        return tickManager;
+    }
+
+    @Override
+    public ThreadManager getThreadManager() {
+        return threadManager;
+    }
+
+    @Override
+    public ConnectionHandler getConnectionHandler() {
+        return connectionHandler;
+    }
+}
diff --git a/src/main/java/com/han/asd/network/Network.java b/src/main/java/com/han/asd/network/Network.java
deleted file mode 100644
index fcce4864d915e6d104c0228c821bae0e5e6755ae..0000000000000000000000000000000000000000
--- a/src/main/java/com/han/asd/network/Network.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package com.han.asd.network;
-
-import com.han.asd.Main;
-import com.han.asd.network.connection.ConnectionHandler;
-import com.han.asd.network.connection.TCPConnection;
-import com.han.asd.network.connection.UDPConnection;
-import com.han.asd.network.exceptions.ConnectionFailedException;
-import com.han.asd.network.exceptions.DisconnectFailedException;
-import com.han.asd.network.exceptions.NetworkConfigurationException;
-import com.han.asd.network.exceptions.SendFailedException;
-import com.han.asd.network.listeners.DiscoveryPacketListener;
-import com.han.asd.network.listeners.DiscoveryResponsePacketListener;
-import com.han.asd.network.packet.Packet;
-import com.han.asd.network.packet.PacketDispatcher;
-import com.han.asd.network.packets.DisconnectPacket;
-import com.han.asd.network.packets.DiscoveryPacket;
-import com.han.asd.network.server.BaseUDPServer;
-import com.han.asd.network.server.MulticastServer;
-import com.han.asd.network.server.TCPServer;
-import com.han.asd.network.server.UDPServer;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-public class Network {
-    private static final Logger logger = LogManager.getLogger(Network.class);
-    private final BaseUDPServer hostServer;
-    private final BaseUDPServer clientServer;
-    private final TCPServer tcpServer;
-    private final PacketDispatcher packetDispatcher;
-    private final InetAddress mcastAddress = InetAddress.getByName("224.0.0.1");
-    private final List<String> hosts = new CopyOnWriteArrayList<>();
-    private TCPConnection tcpConnection;
-    private int port;
-
-    public Network() throws UnknownHostException {
-        packetDispatcher = new PacketDispatcher();
-        packetDispatcher.register(new DiscoveryPacketListener(this));
-        packetDispatcher.register(new DiscoveryResponsePacketListener(this));
-
-        hostServer = new MulticastServer(mcastAddress, packetDispatcher);
-        clientServer = new UDPServer(packetDispatcher);
-        tcpServer = new TCPServer(packetDispatcher);
-
-        logger.info("Network initialized");
-    }
-
-    public void startLobby(int port) throws ConnectionFailedException, SocketException, UnknownHostException {
-        this.port = port;
-
-        hostServer.start(port);
-        tcpServer.start(port);
-
-        logger.info("Lobby started on port: {}", port);
-    }
-
-    public void stopLobby() {
-        port = 0;
-
-        hostServer.stop();
-        tcpServer.stop();
-
-        logger.info("Lobby stopped");
-    }
-
-    public void startDiscovery(int port) {
-        this.port = port;
-
-        try {
-            clientServer.start(Main.TEST_DUNGEON_PORT_2);
-
-            Packet packet = new DiscoveryPacket(InetAddress.getLocalHost().getHostAddress());
-            UDPConnection udpConnection = new UDPConnection(mcastAddress, port);
-            udpConnection.send(packet);
-
-            logger.info("Discovery started");
-        } catch (UnknownHostException | SocketException | SendFailedException e) {
-            logger.error("Failed to start discovery", e);
-        }
-    }
-
-    public void stopDiscovery() {
-        clientServer.stop();
-        logger.info("Discovery stopped");
-    }
-
-    public void connectLobby(String address, int port) throws ConnectionFailedException {
-        try {
-            Socket socket = new Socket(address, port);
-            tcpConnection = new TCPConnection(socket);
-            ConnectionHandler connectionHandler = new ConnectionHandler(packetDispatcher);
-
-            if (tcpConnection.isConnected()) {
-                connectionHandler.start(tcpConnection);
-                logger.info("Connected to lobby at {}:{}", address, port);
-            }
-        } catch (Exception e) {
-            logger.error("Couldn't connect to the specified lobby", e);
-            throw new ConnectionFailedException("Failed to connect to " + address + ":" + port, e);
-        }
-    }
-
-    public void disconnectLobby() throws DisconnectFailedException {
-        port = 0;
-
-        if (tcpConnection == null) {
-            logger.error("Error disconnecting from lobby");
-            return;
-        }
-
-        try {
-            Packet packet = new DisconnectPacket("test");
-            tcpConnection.send(packet);
-
-            if (tcpConnection.isConnected()) {
-                tcpConnection.close();
-                logger.info("Disconnected from lobby");
-            }
-        } catch (SendFailedException e) {
-            logger.error("Error disconnecting from lobby", e);
-            throw new DisconnectFailedException("Couldn't disconnect from the specified lobby", e);
-        }
-    }
-
-    public boolean isConnected() {
-        return tcpConnection != null;
-    }
-
-    public TCPServer getTcpServer() {
-        return tcpServer;
-    }
-
-    public TCPConnection getTcpConnection() {
-        return tcpConnection;
-    }
-
-    public PacketDispatcher getPacketDispatcher() {
-        return packetDispatcher;
-    }
-
-    public int getPort() {
-        return port;
-    }
-
-    public List<String> getHosts() {
-        return hosts;
-    }
-}
diff --git a/src/main/java/com/han/asd/network/connection/Connection.java b/src/main/java/com/han/asd/network/connection/Connection.java
deleted file mode 100644
index c9a20da0f84e0d59789eaea782b33a3002d37678..0000000000000000000000000000000000000000
--- a/src/main/java/com/han/asd/network/connection/Connection.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.han.asd.network.connection;
-
-import com.han.asd.network.exceptions.PacketParsingException;
-import com.han.asd.network.exceptions.ReceiveFailedException;
-import com.han.asd.network.exceptions.SendFailedException;
-import com.han.asd.network.packet.Packet;
-
-public interface Connection {
-    void send(Packet packet) throws SendFailedException;
-
-    Packet receive() throws PacketParsingException, ReceiveFailedException;
-
-    void close();
-
-    boolean isConnected();
-}
diff --git a/src/main/java/com/han/asd/network/connection/ConnectionHandler.java b/src/main/java/com/han/asd/network/connection/ConnectionHandler.java
deleted file mode 100644
index b472a2d17f45e1c931f26aa3e80c0c0cc3b3dd52..0000000000000000000000000000000000000000
--- a/src/main/java/com/han/asd/network/connection/ConnectionHandler.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.han.asd.network.connection;
-
-import com.han.asd.network.exceptions.DispatchPacketException;
-import com.han.asd.network.exceptions.PacketParsingException;
-import com.han.asd.network.exceptions.ReceiveFailedException;
-import com.han.asd.network.packet.Packet;
-import com.han.asd.network.packet.PacketDispatcher;
-import com.han.asd.network.tick.TickManager;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-public class ConnectionHandler implements Runnable {
-    private static final Logger logger = LogManager.getLogger(ConnectionHandler.class);
-    private static final ExecutorService executor = Executors.newFixedThreadPool(2);
-    private final TickManager tickManager;
-    private Connection connection;
-
-    public ConnectionHandler(TickManager tickManager) {
-        this.tickManager = tickManager;
-    }
-
-    public void start(Connection connection) {
-        this.connection = connection;
-        executor.execute(this);
-        logger.info("Connection handler started");
-    }
-
-    @Override
-    public void run() {
-        try {
-            while (connection.isConnected()) {
-                Packet packet = connection.receive();
-                if (packet == null) {
-                    logger.warn("Received null packet, skipping packet dispatch");
-                    continue;
-                }
-                tickManager.getQueue().add(packet);
-                logger.info("Packet dispatched: {}", packet.getClass().getSimpleName());
-            }
-        } catch (ReceiveFailedException e) {
-            logger.error("Server exception in connection handler", e);
-            throw new RuntimeException("ServerException occurred", e);
-        } catch (PacketParsingException e) {
-            logger.error("Invalid packet exception in connection handler", e);
-            throw new RuntimeException("InvalidPacketException occurred", e);
-        } finally {
-            if (!connection.isConnected()) {
-                logger.info("Connection closed");
-            }
-        }
-    }
-
-    public ExecutorService getExecutor() {
-        return executor;
-    }
-
-    public Connection getConnection() {
-        return connection;
-    }
-
-    public void close() {
-        if (connection.isConnected()) {
-            connection.close();
-        }
-
-        executor.shutdown();
-    }
-}
diff --git a/src/main/java/com/han/asd/network/packet/PacketListener.java b/src/main/java/com/han/asd/network/packet/PacketListener.java
deleted file mode 100644
index 7df35385110c878c76d6599f3d9a455d385d543c..0000000000000000000000000000000000000000
--- a/src/main/java/com/han/asd/network/packet/PacketListener.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.han.asd.network.packet;
-
-public interface PacketListener {
-}
\ No newline at end of file
diff --git a/src/main/java/com/han/asd/network/packet/PacketPriority.java b/src/main/java/com/han/asd/network/packet/PacketPriority.java
deleted file mode 100644
index 0ea77c8f02381385eb6a8fcdc513a62e5dacb911..0000000000000000000000000000000000000000
--- a/src/main/java/com/han/asd/network/packet/PacketPriority.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.han.asd.network.packet;
-
-public enum PacketPriority {
-    LOWEST(0),
-    LOW(1),
-    NORMAL(2),
-    HIGH(3),
-    HIGHEST(4),
-    MONITOR(5);
-
-    private final int slot;
-
-    PacketPriority(int slot) {
-        this.slot = slot;
-    }
-
-    public int getSlot() {
-        return slot;
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/com/han/asd/network/server/BaseUDPServer.java b/src/main/java/com/han/asd/network/server/BaseUDPServer.java
deleted file mode 100644
index d64bbdf88623633abcb5a0b21a2327ebc1eec870..0000000000000000000000000000000000000000
--- a/src/main/java/com/han/asd/network/server/BaseUDPServer.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.han.asd.network.server;
-
-import com.han.asd.network.connection.ConnectionHandler;
-import com.han.asd.network.connection.UDPConnection;
-import com.han.asd.network.packet.PacketDispatcher;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import java.net.DatagramSocket;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-
-public abstract class BaseUDPServer implements Server {
-    private static final Logger logger = LogManager.getLogger(BaseUDPServer.class);
-    private final PacketDispatcher packetDispatcher;
-    private DatagramSocket datagramSocket;
-    private UDPConnection udpConnection;
-    private ConnectionHandler connectionHandler;
-
-    public BaseUDPServer(PacketDispatcher packetDispatcher) {
-        this.packetDispatcher = packetDispatcher;
-    }
-
-    public void start(int port, DatagramSocket datagramSocket) throws SocketException {
-        udpConnection = new UDPConnection(datagramSocket);
-
-        connectionHandler = new ConnectionHandler(packetDispatcher);
-        connectionHandler.start(udpConnection);
-
-        this.datagramSocket = datagramSocket;
-        datagramSocket.setBroadcast(true);
-
-        logger.info("UDP server started on port: {}", port);
-    }
-
-    @Override
-    public abstract void start(int port) throws UnknownHostException, SocketException;
-
-    @Override
-    public void stop() {
-        if (connectionHandler != null) {
-            connectionHandler.close();
-        }
-
-        if (udpConnection != null && udpConnection.isConnected()) {
-            udpConnection.close();
-        }
-
-        if (datagramSocket != null && !datagramSocket.isClosed()) {
-            datagramSocket.close();
-        }
-
-        logger.info("UDP server stopped");
-    }
-}
diff --git a/src/main/java/com/han/asd/network/server/Server.java b/src/main/java/com/han/asd/network/server/Server.java
deleted file mode 100644
index 77c14563bbc9a04f24b6f572ee1a3ab5ed503356..0000000000000000000000000000000000000000
--- a/src/main/java/com/han/asd/network/server/Server.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.han.asd.network.server;
-
-import com.han.asd.network.exceptions.ConnectionFailedException;
-import com.han.asd.network.exceptions.NetworkConfigurationException;
-
-import java.net.SocketException;
-import java.net.UnknownHostException;
-
-public interface Server {
-    void start(int port) throws ConnectionFailedException, NetworkConfigurationException, UnknownHostException, SocketException;
-
-    void stop();
-}
diff --git a/src/main/java/com/han/asd/network/server/UDPServer.java b/src/main/java/com/han/asd/network/server/UDPServer.java
deleted file mode 100644
index d7e0cd68d67271c66862395b97527d4e8bcc97d8..0000000000000000000000000000000000000000
--- a/src/main/java/com/han/asd/network/server/UDPServer.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.han.asd.network.server;
-
-import com.han.asd.network.packet.PacketDispatcher;
-
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-
-public class UDPServer extends BaseUDPServer {
-
-    public UDPServer(PacketDispatcher packetDispatcher) {
-        super(packetDispatcher);
-    }
-
-    @Override
-    public void start(int port) throws UnknownHostException, SocketException {
-        DatagramSocket datagramSocket = new DatagramSocket(port, InetAddress.getLocalHost());
-        start(port, datagramSocket);
-    }
-}
diff --git a/src/main/java/com/han/asd/network/tick/Tick.java b/src/main/java/com/han/asd/network/tick/Tick.java
deleted file mode 100644
index 7b02096654f851411d51459ad2cee2740c34d5bd..0000000000000000000000000000000000000000
--- a/src/main/java/com/han/asd/network/tick/Tick.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.han.asd.network.tick;
-
-public class Tick {
-
-    private long timestamp;
-
-    public Tick(long timestamp) {
-        this.timestamp = timestamp;
-    }
-
-    public long getTimestamp() {
-        return timestamp;
-    }
-
-    public void setTimestamp(long timestamp) {
-        this.timestamp = timestamp;
-    }
-}
diff --git a/src/main/java/com/han/asd/network/tick/TickManager.java b/src/main/java/com/han/asd/network/tick/TickManager.java
deleted file mode 100644
index b78edb53e903789d4bf74d343615c460bfc1157a..0000000000000000000000000000000000000000
--- a/src/main/java/com/han/asd/network/tick/TickManager.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.han.asd.network.tick;
-
-import com.han.asd.network.exceptions.DispatchPacketException;
-import com.han.asd.network.packet.Packet;
-import com.han.asd.network.packet.PacketDispatcher;
-
-import java.util.LinkedList;
-import java.util.Queue;
-
-public class TickManager implements Runnable {
-    private Tick tick;
-    private Queue<Packet> queue;
-    private PacketDispatcher packetDispatcher;
-
-    public TickManager(Tick tick, PacketDispatcher packetDispatcher) {
-        this.tick = tick;
-        this.queue = new LinkedList<>();
-        this.packetDispatcher = packetDispatcher;
-    }
-
-    @Override
-    public void run() {
-        try {
-            Packet packet = queue.poll();
-            packetDispatcher.dispatch(packet);
-            Thread.sleep(tick.getTimestamp());
-        } catch (InterruptedException | DispatchPacketException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    public Queue<Packet> getQueue() {
-        return queue;
-    }
-}
diff --git a/src/main/java/com/han/asd/network/packets/ConnectionPacket.java b/src/main/java/com/han/asd/packets/ConnectionPacket.java
similarity index 77%
rename from src/main/java/com/han/asd/network/packets/ConnectionPacket.java
rename to src/main/java/com/han/asd/packets/ConnectionPacket.java
index 88af1d22f5f9448cb6954947cd327cedef3fdb95..dbe11dca06a9572109264c0e06d0add9209e447f 100644
--- a/src/main/java/com/han/asd/network/packets/ConnectionPacket.java
+++ b/src/main/java/com/han/asd/packets/ConnectionPacket.java
@@ -1,6 +1,6 @@
-package com.han.asd.network.packets;
+package com.han.asd.packets;
 
-import com.han.asd.network.packet.Packet;
+import com.han.asd.api.network.packet.Packet;
 
 public class ConnectionPacket extends Packet {
     private final String sourceAddress;
diff --git a/src/main/java/com/han/asd/network/packets/DisconnectPacket.java b/src/main/java/com/han/asd/packets/DisconnectPacket.java
similarity index 77%
rename from src/main/java/com/han/asd/network/packets/DisconnectPacket.java
rename to src/main/java/com/han/asd/packets/DisconnectPacket.java
index 6485e9d1a0caa23cc20d406410bea5dac9ff04c2..0f3692acdfc8da13b581e285a4ddfacef729c083 100644
--- a/src/main/java/com/han/asd/network/packets/DisconnectPacket.java
+++ b/src/main/java/com/han/asd/packets/DisconnectPacket.java
@@ -1,6 +1,6 @@
-package com.han.asd.network.packets;
+package com.han.asd.packets;
 
-import com.han.asd.network.packet.Packet;
+import com.han.asd.api.network.packet.Packet;
 
 public class DisconnectPacket extends Packet {
     private final String sourceAddress;