diff --git a/GServer.Common/.editorconfig b/.editorconfig
similarity index 72%
rename from GServer.Common/.editorconfig
rename to .editorconfig
index 35ee465..c197e14 100644
--- a/GServer.Common/.editorconfig
+++ b/.editorconfig
@@ -14,3 +14,6 @@ csharp_style_namespace_declarations = file_scoped
 
 # CA1051: Do not declare visible instance fields
 dotnet_diagnostic.CA1051.severity = none
+
+# CS8618: Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
+dotnet_diagnostic.CS8618.severity = none
diff --git a/GServer.Common/GServer.Common.csproj b/GServer.Common/GServer.Common.csproj
index dbf1cfd..a8d49b3 100644
--- a/GServer.Common/GServer.Common.csproj
+++ b/GServer.Common/GServer.Common.csproj
@@ -6,8 +6,7 @@
     <Nullable>enable</Nullable>
   </PropertyGroup>
 
-  <ItemGroup>
-    <Folder Include="Enums/" />
+  <ItemGroup>
   </ItemGroup>
 
 </Project>
diff --git a/GServer.Server/GServer.cs b/GServer.Server/GServer.cs
deleted file mode 100644
index b3ce03a..0000000
--- a/GServer.Server/GServer.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System.Net;
-using System.Net.Sockets;
-using GServer.Server.Services;
-
-namespace GServer.Server
-{
-    public class GServer : IDisposable
-    {
-        public readonly UdpClient UdpClient;
-        private IPEndPoint _ipEndpoint;
-
-        private readonly ServerListService _serverListService;
-
-        public GServer(UdpClient udpClient, IPEndPoint ipEndPoint)
-        {
-            UdpClient = udpClient;
-            _ipEndpoint = ipEndPoint;
-
-            UdpClient.Client.SetSocketOption(
-                SocketOptionLevel.Socket,
-                SocketOptionName.ReuseAddress,
-                true);
-
-            _serverListService = new ServerListService();
-        }
-
-        public void Bind()
-        {
-            UdpClient.Client.Bind(_ipEndpoint);
-            Console.WriteLine("Now listening on " + UdpClient.Client.LocalEndPoint);
-        }
-
-        public void Dispose()
-        {
-            UdpClient.Close();
-            UdpClient.Dispose();
-        }
-    }
-}
\ No newline at end of file
diff --git a/GServer.Server/Program.cs b/GServer.Server/Program.cs
index f814c33..bb03612 100644
--- a/GServer.Server/Program.cs
+++ b/GServer.Server/Program.cs
@@ -1,76 +1,20 @@
 using System.Net;
-using System.Net.Sockets;
-using System.Text;
-using GServer.Common;
-using GServer.Common.Networking.Enums;
-using GServer.Common.Networking.Messages.Client;
-using GServer.Common.Networking.Messages.Server;
+using GServer.Server;
 
 internal class Program
 {
     private const int LISTEN_PORT = 11000;
 
+
     private static void Main(string[] args)
     {
+        UDPGameServer udpGameServer = new(new IPEndPoint(IPAddress.Any, LISTEN_PORT));
 
-        GServer.Server.GServer server = new(
-            new UdpClient(),
-            new IPEndPoint(IPAddress.Any, LISTEN_PORT));
+        udpGameServer.Start();
 
-        server.Bind();
-
-        try
+        while (true)
         {
-            IPEndPoint remoteEP = new(IPAddress.Any, 0);
-
-            while (true)
-            {
-                Console.WriteLine("Waiting for message...");
-
-                byte[] bytes = server.UdpClient.Receive(ref remoteEP);
-                string ASCIIContent = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
-
-                Console.WriteLine("Received from: " + remoteEP);
-                Console.WriteLine($"Length = {bytes.Length}, Content = {ASCIIContent}");
-
-                var stream = new MessageMemoryStream(bytes);
-
-                ServerPacketIn serverPacketIn = (ServerPacketIn)stream.ReadByte();
-
-                switch (serverPacketIn)
-                {
-                    case ServerPacketIn.AUTH:
-                        var msg = new AuthMessage(stream);
-
-                        AuthResponseMessage resp;
-
-                        if (msg.Username == "aaronyarbz" && msg.Password == "password123")
-                        {
-                            resp = new(true, Guid.NewGuid().ToString(), null);
-                        }
-                        else
-                        {
-                            resp = new(false, null, AuthResponseFailure.IncorrectLoginOrPassword);
-                        }
-
-                        server.UdpClient.Send(resp.Serialize(), remoteEP);
-
-                        break;
-
-                    default:
-                        Console.WriteLine($"Received unsupported packet.");
-                        break;
-                }
-            }
-        }
-        catch (Exception ex)
-        {
-            Console.WriteLine(ex);
-        }
-        finally
-        {
-            Console.WriteLine("Disposing of server...");
-            server.Dispose();
+            _ = udpGameServer.ProcessAsync();
         }
     }
 }
\ No newline at end of file
diff --git a/GServer.Server/UDPGameServer.cs b/GServer.Server/UDPGameServer.cs
new file mode 100644
index 0000000..acacbae
--- /dev/null
+++ b/GServer.Server/UDPGameServer.cs
@@ -0,0 +1,90 @@
+using System.Net;
+using System.Net.Sockets;
+using GServer.Common;
+using GServer.Common.Networking.Enums;
+using GServer.Common.Networking.Messages.Client;
+using GServer.Common.Networking.Messages.Server;
+
+namespace GServer.Server;
+
+public class UDPGameServer : IDisposable
+{
+    public readonly UdpClient UdpClient;
+
+    private readonly IPEndPoint _endPoint;
+
+    public UDPGameServer(IPEndPoint endPoint)
+    {
+        _endPoint = endPoint;
+
+        UdpClient = new UdpClient();
+        UdpClient.Client.SetSocketOption(
+            SocketOptionLevel.Socket,
+            SocketOptionName.ReuseAddress,
+            true);
+    }
+
+    /// <summary>
+    /// Bind the server to the given endpoint.
+    /// </summary>
+    public void Start()
+    {
+        UdpClient.Client.Bind(_endPoint);
+        Console.WriteLine($"UDPGameServer listening on {_endPoint}");
+    }
+
+    /// <summary>
+    /// Begin processing messages
+    /// </summary>
+    /// <returns></returns>
+    public async Task ProcessAsync()
+    {
+        try
+        {
+            UdpReceiveResult res = await UdpClient.ReceiveAsync();
+            byte[] bytes = res.Buffer;
+            MessageMemoryStream stream = new(bytes);
+            await HandleMessageAsync(stream, res.RemoteEndPoint);
+        }
+        catch (Exception ex)
+        {
+            Console.WriteLine(ex);
+        }
+    }
+
+    private async Task HandleMessageAsync(MessageMemoryStream stream, IPEndPoint remoteEndPoint)
+    {
+        ServerPacketIn serverPacketIn = (ServerPacketIn)stream.ReadByte();
+
+        Console.WriteLine($"Handling message {serverPacketIn} from {remoteEndPoint}...");
+
+        switch (serverPacketIn)
+        {
+            case ServerPacketIn.AUTH:
+                AuthMessage msg = new(stream);
+
+                AuthResponseMessage resp = msg.Username == "aaronyarbz" && msg.Password == "password123"
+                    ? new(true, Guid.NewGuid().ToString(), null)
+                    : new(false, null, AuthResponseFailure.IncorrectLoginOrPassword);
+
+                byte[] buffer = resp.Serialize();
+                _ = await UdpClient.SendAsync(buffer, buffer.Length, remoteEndPoint);
+
+                break;
+
+            case ServerPacketIn.LIST_SERVERS:
+                throw new NotImplementedException();
+
+            default:
+                Console.WriteLine($"Received unsupported packet.");
+                break;
+        }
+    }
+
+    public void Dispose()
+    {
+        UdpClient.Close();
+        UdpClient.Dispose();
+        GC.SuppressFinalize(this);
+    }
+}
\ No newline at end of file
diff --git a/GServer.sln b/GServer.sln
index e6bac6a..e661656 100644
--- a/GServer.sln
+++ b/GServer.sln
@@ -14,9 +14,6 @@ Global
 		Debug|Any CPU = Debug|Any CPU
 		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 		{14D7D62B-C48B-4F6B-83F4-0CAFA8A7D6D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{14D7D62B-C48B-4F6B-83F4-0CAFA8A7D6D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
@@ -31,4 +28,7 @@ Global
 		{C105363D-E719-4296-94A2-01170E603889}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{C105363D-E719-4296-94A2-01170E603889}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
 EndGlobal