diff --git a/.gitignore b/.gitignore
index 983976e1..e855f22f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,6 @@
 #docs backup files
 /docs/~$NetworkFlow.drawio.bkp
 /docs/~$NetworkFlow.drawio.dtmp
+
+#saves
+/saves/arena
diff --git a/Scripts/auth/createAuthTables.sql b/Scripts/auth/createAuthTables.sql
new file mode 100644
index 00000000..d2178b1e
--- /dev/null
+++ b/Scripts/auth/createAuthTables.sql
@@ -0,0 +1,7 @@
+
+-- accounts definition
+CREATE TABLE accounts (
+	id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+	username TEXT NOT NULL,
+	pwdhash TEXT NOT NULL
+);
diff --git a/Scripts/auth/retrievePassHash.sql b/Scripts/auth/retrievePassHash.sql
new file mode 100644
index 00000000..8342c77a
--- /dev/null
+++ b/Scripts/auth/retrievePassHash.sql
@@ -0,0 +1,3 @@
+
+--given username=testusername
+SELECT pwdhash FROM accounts WHERE username='testusername';
diff --git a/Scripts/character/createCharacterTables.sql b/Scripts/character/createCharacterTables.sql
new file mode 100644
index 00000000..f8527697
--- /dev/null
+++ b/Scripts/character/createCharacterTables.sql
@@ -0,0 +1,10 @@
+
+--characters
+--positions
+CREATE TABLE charaWorldPositions (playerId INTEGER PRIMARY KEY, id INTEGER, posX INTEGER, posY INTEGER);
+CREATE INDEX charaWorldPositionsIDIndex ON charaWorldPositions (id);
+CREATE INDEX charaWorldPositionsPosIndex ON charaWorldPositions (posX, posY);
+
+--data
+CREATE TABLE charaData (playerId INTEGER PRIMARY KEY, id INTEGER, dataVal VARCHAR);
+CREATE INDEX charaDataIDIndex ON charaData (id);
diff --git a/Scripts/createTables.sql b/Scripts/createTables.sql
index 271e1788..584cb3cb 100644
--- a/Scripts/createTables.sql
+++ b/Scripts/createTables.sql
@@ -3,36 +3,7 @@
 CREATE TABLE mainTable (propName VARCHAR PRIMARY KEY, propValue VARCHAR);
 INSERT INTO mainTable (propName, propValue) VALUES ("ver","1");
 
---characters
---positions
-CREATE TABLE charaWorldPositions (id INTEGER PRIMARY KEY, charID INTEGER, posX INTEGER, posY INTEGER);
-CREATE INDEX charaWorldPositionsIDIndex ON charaWorldPositions (charID);
-CREATE INDEX charaWorldPositionsPosIndex ON charaWorldPositions (posX, posY);
-
---data
-CREATE TABLE charaData (id INTEGER PRIMARY KEY, charID INTEGER, dataVal VARCHAR);
-CREATE INDEX charaDataIDIndex ON charaData (charID);
 
 
 
---towns
---positions
-CREATE TABLE townWorldPositions (id INTEGER PRIMARY KEY, townID INTEGER, posX INTEGER, posY INTEGER);
-CREATE INDEX townWorldPositionsIDIndex ON townWorldPositions (townID);
-CREATE INDEX townWorldPositionsPosIndex ON townWorldPositions (posX, posY);
-
---data
-CREATE TABLE townData (id INTEGER PRIMARY KEY, townID INTEGER, dataVal VARCHAR);
-CREATE INDEX townDataIDIndex ON townData (townID);
-
-
---structures
---positions
-CREATE TABLE structWorldPositions (id INTEGER PRIMARY KEY, structID INTEGER, posX INTEGER, posY INTEGER);
-CREATE INDEX structWorldPositionsIDIndex ON structWorldPositions (structID);
-CREATE INDEX structWorldPositionsPosIndex ON structWorldPositions (posX, posY);
-
---data
-CREATE TABLE structData (id INTEGER PRIMARY KEY, structID INTEGER, dataVal VARCHAR);
-CREATE INDEX structDataIDIndex ON structData (structID);
 
diff --git a/Scripts/structs/createStructsTables.sql b/Scripts/structs/createStructsTables.sql
new file mode 100644
index 00000000..4e473cb2
--- /dev/null
+++ b/Scripts/structs/createStructsTables.sql
@@ -0,0 +1,10 @@
+
+--structures
+--positions
+CREATE TABLE structWorldPositions (id INTEGER PRIMARY KEY, structID INTEGER, posX INTEGER, posY INTEGER);
+CREATE INDEX structWorldPositionsIDIndex ON structWorldPositions (structID);
+CREATE INDEX structWorldPositionsPosIndex ON structWorldPositions (posX, posY);
+
+--data
+CREATE TABLE structData (id INTEGER PRIMARY KEY, structID INTEGER, dataVal VARCHAR);
+CREATE INDEX structDataIDIndex ON structData (structID);
diff --git a/Scripts/towns/createTownsTables.sql b/Scripts/towns/createTownsTables.sql
new file mode 100644
index 00000000..5f03b3e7
--- /dev/null
+++ b/Scripts/towns/createTownsTables.sql
@@ -0,0 +1,10 @@
+
+--towns
+--positions
+CREATE TABLE townWorldPositions (id INTEGER PRIMARY KEY, townID INTEGER, posX INTEGER, posY INTEGER);
+CREATE INDEX townWorldPositionsIDIndex ON townWorldPositions (townID);
+CREATE INDEX townWorldPositionsPosIndex ON townWorldPositions (posX, posY);
+
+--data
+CREATE TABLE townData (id INTEGER PRIMARY KEY, townID INTEGER, dataVal VARCHAR);
+CREATE INDEX townDataIDIndex ON townData (townID);
diff --git a/pom.xml b/pom.xml
index c6be2534..c0302428 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,111 +12,126 @@
         3.2.3
         1.9.19
     
+
     
-        
-        
-            org.lwjgl
-            lwjgl
-            ${lwjgl.version}
-        
-        
-            org.lwjgl
-            lwjgl-assimp
-            ${lwjgl.version}
-        
-        
-            org.lwjgl
-            lwjgl-glfw
-            ${lwjgl.version}
-        
-        
-            org.lwjgl
-            lwjgl-opengl
-            ${lwjgl.version}
-        
-        
-            org.lwjgl
-            lwjgl-opengles
-            ${lwjgl.version}
-        
-        
-            org.lwjgl
-            lwjgl-openal
-            ${lwjgl.version}
-        
-        
-            org.lwjgl
-            lwjgl-stb
-            ${lwjgl.version}
-        
         
+        
         
             org.lwjgl
             lwjgl
             ${lwjgl.version}
             ${lwjgl.natives}
-            runtime
         
-        
+        
+            org.lwjgl
+            lwjgl
+            ${lwjgl.version}
+            ${lwjgl.natives}
+            import
+        
+
+        
+        
+        
+            org.lwjgl
+            lwjgl-assimp
+            ${lwjgl.version}
+        
         
             org.lwjgl
             lwjgl-assimp
             ${lwjgl.version}
             ${lwjgl.natives}
-            runtime
         
-        
+
+        
+        
+        
+            org.lwjgl
+            lwjgl-glfw
+            ${lwjgl.version}
+        
         
             org.lwjgl
             lwjgl-glfw
             ${lwjgl.version}
             ${lwjgl.natives}
-            runtime
         
-        
+
+        
+        
+        
+            org.lwjgl
+            lwjgl-opengl
+            ${lwjgl.version}
+        
         
             org.lwjgl
             lwjgl-opengl
             ${lwjgl.version}
             ${lwjgl.natives}
-            runtime
         
-        
+
+        
+        
+        
+            org.lwjgl
+            lwjgl-opengles
+            ${lwjgl.version}
+        
         
             org.lwjgl
             lwjgl-opengles
             ${lwjgl.version}
             ${lwjgl.natives}
-            runtime
         
-        
+
+        
+        
+        
+            org.lwjgl
+            lwjgl-openal
+            ${lwjgl.version}
+        
         
             org.lwjgl
             lwjgl-openal
             ${lwjgl.version}
             ${lwjgl.natives}
-            runtime
+        
+
+        
+        
+        
+            org.lwjgl
+            lwjgl-stb
+            ${lwjgl.version}
         
         
             org.lwjgl
             lwjgl-stb
             ${lwjgl.version}
             ${lwjgl.natives}
-            runtime
         
+        
+        
+        
         
             org.joml
             joml
             ${joml.version}
         
 
-
+        
+        
         
             com.google.code.gson
             gson
             2.8.6
         
 
+        
+        
         
-
-        
-        
-            org.apache.commons
-            commons-crypto
-            1.1.0
-        
-
+        
+        
         
         
             org.xerial
@@ -190,38 +191,7 @@
         
     
     
-        
-            
-                ${basedir}/src/main/resources
-                
-                    **/*
-                
-            
-        
         
-            
-                maven-assembly-plugin
-                
-                    
-                        
-                            true
-                            electrosphere.main.Main
-                        
-                    
-                    
-                        jar-with-dependencies
-                    
-                
-                
-                    
-                        assemble-all
-                        package
-                        
-                            single
-                        
-                    
-                
-            
             
                 org.apache.maven.plugins
                 maven-shade-plugin
diff --git a/src/main/java/electrosphere/auth/AuthenticationManager.java b/src/main/java/electrosphere/auth/AuthenticationManager.java
index 52863353..503a6039 100644
--- a/src/main/java/electrosphere/auth/AuthenticationManager.java
+++ b/src/main/java/electrosphere/auth/AuthenticationManager.java
@@ -1,11 +1,81 @@
 package electrosphere.auth;
 
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.Arrays;
+import java.util.Base64;
+
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
+import electrosphere.game.server.db.DatabaseResult;
+import electrosphere.game.server.db.DatabaseResultRow;
+import electrosphere.logger.LoggerInterface;
+import electrosphere.main.Globals;
+
 public class AuthenticationManager {
     
 
     public boolean authenticate(String username, String password){
-        boolean rVal = true;
-        //TODO: actually authenticate
+        //first we hash the input password
+        String hashedPassword = getHashedString(password);
+        //then query the database for the username and hash for the input username
+        DatabaseResult result = Globals.dbController.executePreparedQuery("SELECT id, username, pwdhash FROM accounts WHERE username=?;",username);
+        if(result.hasResult()){
+            boolean foundRow = false;
+            //if we get a valid response from the database, check that it actually matches hashes
+            for(DatabaseResultRow row : result){
+                foundRow = true;
+                String pwdhash = row.getAsString("pwdhash");
+                if(pwdhash.equals(hashedPassword)){
+                    LoggerInterface.loggerAuth.INFO("Authenticated user " + username);
+                    return true;
+                }
+            }
+            //If we didn't find a single account, go ahead and create it
+            if(!foundRow){
+                LoggerInterface.loggerAuth.INFO("Created user " + username);
+                Globals.dbController.executePreparedStatement("INSERT INTO accounts (username, pwdhash) VALUES(?, ?);",username,hashedPassword);
+                //TODO: verify we created the account
+                return true;
+            }
+        }
+        LoggerInterface.loggerAuth.INFO("Failed to authenticate user " + username);
+        return false;
+    }
+
+    static final int saltLength = 16;
+    public static String getHashedString(String input){
+        String rVal = "";
+
+        //generate salt
+        char[] charArray = input.toCharArray();
+        byte[] salt = new byte[saltLength];
+        for(int i = 0; i < saltLength; i++){
+            if(i < charArray.length){
+                salt[i] = (byte)charArray[i];
+            } else {
+                salt[i] = (byte)i;
+            }
+        }
+
+        //perform hash
+        KeySpec spec = new PBEKeySpec(charArray, salt, 65536, 512);
+        try {
+            SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
+            byte[] hash = f.generateSecret(spec).getEncoded();
+            Base64.Encoder enc = Base64.getEncoder();
+            // System.out.printf("salt: %s%n", enc.encodeToString(salt));
+            // System.out.printf("hash: %s%n", enc.encodeToString(hash));
+            // System.out.println(Arrays.toString(hash));
+            rVal = enc.encodeToString(hash);
+        } catch (NoSuchAlgorithmException e) {
+            LoggerInterface.loggerAuth.ERROR("NoSuchAlgorithmException in hash string", e);
+        } catch (InvalidKeySpecException e) {
+            LoggerInterface.loggerAuth.ERROR("InvalidKeySpecException in hash string", e);
+        }
+        
         return rVal;
     }
 
diff --git a/src/main/java/electrosphere/controls/ControlHandler.java b/src/main/java/electrosphere/controls/ControlHandler.java
index 88d479c3..49080ce2 100644
--- a/src/main/java/electrosphere/controls/ControlHandler.java
+++ b/src/main/java/electrosphere/controls/ControlHandler.java
@@ -773,7 +773,7 @@ public class ControlHandler {
         controls.get(INPUT_CODE_CHARACTER_OPEN).setOnClick(new ControlMethod(){public void execute(){
             if(InventoryUtils.hasEquipInventory(Globals.playerEntity) && Globals.elementManager.getWindow(WindowStrings.WINDOW_CHARACTER) == null){
                 //create window
-                Window mainMenuWindow = MenuGenerators.createCharacterMenu(InventoryUtils.getEquipInventory(Globals.playerEntity));
+                Window mainMenuWindow = MenuGenerators.createCharacterInventoryMenu(InventoryUtils.getEquipInventory(Globals.playerEntity));
                 //register
                 Globals.elementManager.registerWindow(WindowStrings.WINDOW_CHARACTER, mainMenuWindow);
                 //make visible
diff --git a/src/main/java/electrosphere/engine/LoadingThread.java b/src/main/java/electrosphere/engine/LoadingThread.java
index eaad8044..966c23a0 100644
--- a/src/main/java/electrosphere/engine/LoadingThread.java
+++ b/src/main/java/electrosphere/engine/LoadingThread.java
@@ -36,6 +36,7 @@ import electrosphere.game.server.terrain.models.TerrainModification;
 import electrosphere.game.server.town.Town;
 import electrosphere.game.server.world.MacroData;
 import electrosphere.game.server.datacell.DataCellManager;
+import electrosphere.game.server.db.DatabaseUtils;
 import electrosphere.game.simulation.MicroSimulation;
 import electrosphere.logger.LoggerInterface;
 import electrosphere.main.Globals;
@@ -65,8 +66,12 @@ import electrosphere.game.server.unit.UnitUtils;
 import electrosphere.renderer.ui.DrawableElement;
 import electrosphere.renderer.ui.WidgetUtils;
 import electrosphere.renderer.ui.Window;
+import electrosphere.util.FileUtils;
 import electrosphere.util.Utilities;
 
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Random;
@@ -183,6 +188,12 @@ public class LoadingThread extends Thread {
                 initServerArenaWorldData();
                 //init data cell manager
                 initDataCellManager();
+                //for testing purposes
+                FileUtils.recursivelyDelete("/home/satellite/temp/saves/arena");
+                //init database connection
+                SaveUtils.initSave("arena");
+                //connect to database
+                SaveUtils.loadSave("arena");
                 //init authentication
                 initAuthenticationManager();
                 //initialize the server thread (server only)
@@ -416,7 +427,6 @@ public class LoadingThread extends Thread {
         Thread clientThread = null;
         if(Globals.RUN_CLIENT){
             Globals.clientConnection = new ClientNetworking(NetUtils.getAddress(),NetUtils.getPort());
-            System.out.println(Globals.clientConnection.socket);
             clientThread = new Thread(Globals.clientConnection);
             clientThread.start();
         }
diff --git a/src/main/java/electrosphere/game/server/db/DatabaseController.java b/src/main/java/electrosphere/game/server/db/DatabaseController.java
index bb9fde28..04d2407c 100644
--- a/src/main/java/electrosphere/game/server/db/DatabaseController.java
+++ b/src/main/java/electrosphere/game/server/db/DatabaseController.java
@@ -30,41 +30,74 @@ public class DatabaseController {
             conn = DriverManager.getConnection(fullAddress, connectionProps);
         } catch (SQLException ex) {
             LoggerInterface.loggerFileIO.ERROR("Failure to connect to db", ex);
+            ex.printStackTrace();
         }
     }
-    
-//    public boolean executeStatement(String statementRaw){
-//        boolean rVal = false;
-//        try {
-//            PreparedStatement statement = conn.prepareStatement(statementRaw);
-//            rVal = statement.execute();
-//        } catch (SQLException ex) {
-//            LoggerInterface.loggerFileIO.ERROR("SQL statement execution error", ex);
-//        }
-//        return rVal;
-//    }
-    
-    public DatabaseResult executeStatement(String statementRaw){
-        DatabaseResult rVal = DatabaseResult.createStatement(statementRaw);
+
+    /**
+     * Executes a write statement to the database
+     * @param statementRaw The raw string for the statement
+     * @param arguments The arguments to be inserted into the raw sql
+     */
+    public boolean executePreparedStatement(String statementRaw, Object...arguments){
         try {
             PreparedStatement statement = conn.prepareStatement(statementRaw);
-            statement.execute();
-            ResultSet results = statement.getResultSet();
-            if(results != null){
-                rVal.addResultSet(results);
+            //Set arguments for prepared statements
+            int argumentIndex = 1;
+            for(Object currentArg : arguments){
+                if(currentArg instanceof String){
+                    statement.setString(argumentIndex, (String)currentArg);
+                } else if(currentArg instanceof Integer){
+                    statement.setInt(argumentIndex, (int)currentArg);
+                } else if(currentArg instanceof Float){
+                    statement.setFloat(argumentIndex, (float)currentArg);
+                } else if(currentArg instanceof Boolean){
+                    statement.setBoolean(argumentIndex, (boolean)currentArg);
+                } else if(currentArg instanceof Long){
+                    statement.setLong(argumentIndex, (long)currentArg);
+                } else if(currentArg instanceof Double){
+                    statement.setDouble(argumentIndex, (double)currentArg);
+                }
+                argumentIndex++;
             }
+            //actually execute
+            return statement.execute();
         } catch (SQLException ex) {
-            rVal.succeeded = false;
-            rVal.hasResultSet = false;
-            LoggerInterface.loggerFileIO.ERROR("SQL statement execution error", ex);
+            LoggerInterface.loggerFileIO.ERROR("SQL query execution error", ex);
         }
-        return rVal;
+        return false;
     }
-    
-    public DatabaseResult executeQuery(String statementRaw){
-        DatabaseResult rVal = DatabaseResult.createStatement(statementRaw);
+
+    /**
+     * Executes a query against the database
+     * @param statementRaw The raw sql
+     * @param arguments The arguments to be injected into the raw sql
+     * @return A DatabaseResult representing the results of the query, or null if there was no result
+     */
+    public DatabaseResult executePreparedQuery(String statementRaw, Object...arguments){
+        DatabaseResult rVal = DatabaseResult.createQuery(statementRaw);
         try {
             PreparedStatement statement = conn.prepareStatement(statementRaw);
+
+            //Set arguments for prepared statements
+            int argumentIndex = 1;
+            for(Object currentArg : arguments){
+                if(currentArg instanceof String){
+                    statement.setString(argumentIndex, (String)currentArg);
+                } else if(currentArg instanceof Integer){
+                    statement.setInt(argumentIndex, (int)currentArg);
+                } else if(currentArg instanceof Float){
+                    statement.setFloat(argumentIndex, (float)currentArg);
+                } else if(currentArg instanceof Boolean){
+                    statement.setBoolean(argumentIndex, (boolean)currentArg);
+                } else if(currentArg instanceof Long){
+                    statement.setLong(argumentIndex, (long)currentArg);
+                } else if(currentArg instanceof Double){
+                    statement.setDouble(argumentIndex, (double)currentArg);
+                }
+                argumentIndex++;
+            }
+            //actually execute
             ResultSet results = statement.executeQuery();
             if(results != null){
                 rVal.addResultSet(results);
@@ -79,6 +112,9 @@ public class DatabaseController {
     
     public boolean isConnected(){
         boolean rVal = false;
+        if(conn == null){
+            return false;
+        }
         try {
             rVal = conn.isValid(100);
         } catch (SQLException ex) {
diff --git a/src/main/java/electrosphere/game/server/db/DatabaseResult.java b/src/main/java/electrosphere/game/server/db/DatabaseResult.java
index 4c7c5626..e9a660e9 100644
--- a/src/main/java/electrosphere/game/server/db/DatabaseResult.java
+++ b/src/main/java/electrosphere/game/server/db/DatabaseResult.java
@@ -4,6 +4,7 @@ import com.google.gson.Gson;
 import electrosphere.logger.LoggerInterface;
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.util.Iterator;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -11,7 +12,8 @@ import java.util.logging.Logger;
  *
  * @author amaterasu
  */
-public class DatabaseResult {
+public class DatabaseResult implements Iterable {
+
     boolean isQuery = false;
     boolean isStatement = false;
     boolean succeeded = false;
@@ -25,29 +27,30 @@ public class DatabaseResult {
     }
     
     
-    public static DatabaseResult createQuery(String code){
+    protected static DatabaseResult createQuery(String code){
         DatabaseResult rVal = new DatabaseResult();
         rVal.isQuery = true;
         rVal.code = code;
         return rVal;
     }
     
-    public static DatabaseResult createStatement(String code){
+    protected static DatabaseResult createStatement(String code){
         DatabaseResult rVal = new DatabaseResult();
         rVal.isStatement = true;
         rVal.code = code;
         return rVal;
     }
     
-    public void addResultSet(ResultSet rs){
+    protected void addResultSet(ResultSet rs){
+        hasResultSet = true;
         this.rs = rs;
     }
     
-    public ResultSet getResultSet(){
+    protected ResultSet getResultSet(){
         return rs;
     }
     
-    public boolean hasResultSet(){
+    public boolean hasResult(){
         return hasResultSet;
     }
     
@@ -77,4 +80,9 @@ public class DatabaseResult {
     
     public void logRawResult(){
     }
+
+    @Override
+    public DatabaseResultIterator iterator() {
+        return new DatabaseResultIterator(rs);
+    }
 }
diff --git a/src/main/java/electrosphere/game/server/db/DatabaseResultIterator.java b/src/main/java/electrosphere/game/server/db/DatabaseResultIterator.java
new file mode 100644
index 00000000..02f0baea
--- /dev/null
+++ b/src/main/java/electrosphere/game/server/db/DatabaseResultIterator.java
@@ -0,0 +1,98 @@
+package electrosphere.game.server.db;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import electrosphere.logger.LoggerInterface;
+
+public class DatabaseResultIterator implements Iterator {
+
+    ResultSet rs;
+    ResultSetMetaData metadata;
+    List typeList;
+    
+    /**
+     * Creates a result iterator -- used internal to package
+     * @param result
+     */
+    protected DatabaseResultIterator(ResultSet result){
+        this.rs = result;
+        try {
+            this.metadata = this.rs.getMetaData();
+            int columnCount = metadata.getColumnCount();
+            this.typeList = new LinkedList();
+            for(int i = 0; i < columnCount; i++){
+                //result sets are indexed starting at 1
+                this.typeList.add(metadata.getColumnType(i+1));
+            }
+            //the sqlite driver doesn't support reverse navigation unfortunatelly
+            //if it did, we'd call this to be explicitly clear where we want to start
+            //instead the assumption is it always starts ON the first element
+            // this.rs.first();
+        } catch (SQLException e) {
+            LoggerInterface.loggerEngine.ERROR("SQL Exception", e);
+        }
+
+    }
+
+    /**
+     * Lets us know if the result has a next value
+     */
+    @Override
+    public boolean hasNext() {
+        try {
+            return !rs.isAfterLast();
+        } catch (SQLException e) {
+            LoggerInterface.loggerEngine.ERROR("Critical failure in DatabaseResultIterator", e);
+            return false;
+        }
+    }
+
+    /**
+     * Gets the next value in the result
+     */
+    @Override
+    public DatabaseResultRow next() {
+        DatabaseResultRow row = new DatabaseResultRow();
+        int columnIncrementer = 0;
+        //basically go through each type and add it to the row object that we return
+        //the types are stored in the typeList field on this object when it is created
+        try {
+            for(int type : typeList){
+                //increment at the beginning because result sets are indexed starting at 1
+                columnIncrementer++;
+                switch(type){
+                    case Types.INTEGER:
+                    row.putValue(metadata.getColumnName(columnIncrementer), rs.getInt(columnIncrementer));
+                    break;
+                    case Types.VARCHAR:
+                    row.putValue(metadata.getColumnName(columnIncrementer), rs.getString(columnIncrementer));
+                    break;
+                    case Types.BIGINT:
+                    row.putValue(metadata.getColumnName(columnIncrementer), rs.getLong(columnIncrementer));
+                    break;
+                    case Types.FLOAT:
+                    row.putValue(metadata.getColumnName(columnIncrementer), rs.getFloat(columnIncrementer));
+                    break;
+                    case Types.DOUBLE:
+                    row.putValue(metadata.getColumnName(columnIncrementer), rs.getDouble(columnIncrementer));
+                    break;
+                    default:
+                    LoggerInterface.loggerEngine.WARNING("Unsupported type from database in DatabaseResultIterator " + type);
+                    break;
+                }
+            }
+            //make sure to increment the result set so we don't infinitely loop the first element
+            this.rs.next();
+        } catch (SQLException e){
+            LoggerInterface.loggerEngine.ERROR("Unhandled SQL exception", e);
+        }
+        return row;
+    }
+    
+}
diff --git a/src/main/java/electrosphere/game/server/db/DatabaseResultRow.java b/src/main/java/electrosphere/game/server/db/DatabaseResultRow.java
new file mode 100644
index 00000000..97534560
--- /dev/null
+++ b/src/main/java/electrosphere/game/server/db/DatabaseResultRow.java
@@ -0,0 +1,76 @@
+package electrosphere.game.server.db;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class DatabaseResultRow {
+    
+    // protected addColumn(int column)
+
+    //stores all the values of the row in an easily indexible-by-column-name format
+    Map values = new HashMap();
+
+    /**
+     * Used internally for putting values into the row
+     * @param columnName
+     * @param value
+     */
+    protected void putValue(String columnName, Object value){
+        values.put(columnName,value);
+    }
+
+    /**
+     * Gets the given value
+     * @param columnName the name of the column to check
+     * @return the value on said column
+     */
+    public Object getValue(String columnName){
+        return values.get(columnName);
+    }
+
+    /**
+     * Gets the given value as a string
+     * @param columnName the name of the column to check
+     * @return the value on said column as a string
+     */
+    public String getAsString(String columnName){
+        return (String)values.get(columnName);
+    }
+
+    /**
+     * Gets the given value as an integer
+     * @param columnName the name of the column to check
+     * @return the value on said column as an integer
+     */
+    public int getAsInteger(String columnName){
+        return (Integer)values.get(columnName);
+    }
+
+    /**
+     * Gets the given value as a long
+     * @param columnName the name of the column to check
+     * @return the value on said column as a long
+     */
+    public long getAsLong(String columnName){
+        return (Long)values.get(columnName);
+    }
+
+    /**
+     * Gets the given value as a float
+     * @param columnName the name of the column to check
+     * @return the value on said column as a float
+     */
+    public float getAsFloat(String columnName){
+        return (Float)values.get(columnName);
+    }
+
+    /**
+     * Gets the given value as a double
+     * @param columnName the name of the column to check
+     * @return the value on said column as a double
+     */
+    public double getAsDouble(String columnName){
+        return (Double)values.get(columnName);
+    }
+
+}
diff --git a/src/main/java/electrosphere/game/server/db/DatabaseUtils.java b/src/main/java/electrosphere/game/server/db/DatabaseUtils.java
index 5ab2f009..963e846c 100644
--- a/src/main/java/electrosphere/game/server/db/DatabaseUtils.java
+++ b/src/main/java/electrosphere/game/server/db/DatabaseUtils.java
@@ -1,6 +1,7 @@
 package electrosphere.game.server.db;
 
 import electrosphere.logger.LoggerInterface;
+import electrosphere.main.Globals;
 import electrosphere.util.FileUtils;
 import java.io.IOException;
 import java.util.logging.Level;
@@ -11,29 +12,58 @@ import java.util.logging.Logger;
  * @author satellite
  */
 public class DatabaseUtils {
+
+    
     public static boolean initCentralDBFile(String path){
-        String sanitizedPath = "." + FileUtils.sanitizeFilePath(path);
+        String sanitizedPath = FileUtils.sanitizeFilePath(path);
         if(!FileUtils.checkFileExists(sanitizedPath)){
             return false;
         }
         String dbFilePath = sanitizedPath + "/central.db";
-        DatabaseController controller = new DatabaseController();
-        controller.connect(dbFilePath);
+        if(Globals.dbController == null){
+            Globals.dbController = new DatabaseController();
+        }
+        if(!Globals.dbController.isConnected()){
+            Globals.dbController.connect(dbFilePath);
+        }
+        runScript(Globals.dbController,"createTables.sql");
+        //both of these are used for arena mode as well as main game
+        runScript(Globals.dbController,"/auth/createAuthTables.sql");
+        runScript(Globals.dbController,"/character/createCharacterTables.sql");
+        //create adventure-only files
+        if(!dbFilePath.equals("./saves/arena/central.db")){
+            //we only want to create these if we're not in arena mode
+            runScript(Globals.dbController,"/towns/createTownsTables.sql");
+            runScript(Globals.dbController,"/structs/createStructsTables.sql");
+        }
+        Globals.dbController.disconnect();
+        return true;
+    }
+
+    public static boolean runScript(DatabaseController controller, String scriptPath){
         String rawScript = "";
         try {
-            rawScript = FileUtils.getSQLScriptFileAsString("createTables.sql");
+            rawScript = FileUtils.getSQLScriptFileAsString(scriptPath);
         } catch (IOException ex) {
             LoggerInterface.loggerEngine.ERROR("Failure reading create db script", ex);
             return false;
         }
         String[] scriptLines = rawScript.split("\n");
+        String accumulatorString = "";
         for(String line : scriptLines){
             if(line.length() > 1 && !line.startsWith("--")){
-                System.out.println("EXECUTE: " + line);
-                controller.executeStatement(line);
+                if(line.contains(";")){
+                    accumulatorString = accumulatorString + line;
+                    System.out.println("EXECUTE: " + accumulatorString);
+                    controller.executePreparedStatement(accumulatorString);
+                    accumulatorString = "";
+                } else {
+                    accumulatorString = accumulatorString + line;
+                }
             }
         }
-        controller.disconnect();
         return true;
     }
+
+
 }
diff --git a/src/main/java/electrosphere/game/server/saves/SaveUtils.java b/src/main/java/electrosphere/game/server/saves/SaveUtils.java
index 29661e47..56bef734 100644
--- a/src/main/java/electrosphere/game/server/saves/SaveUtils.java
+++ b/src/main/java/electrosphere/game/server/saves/SaveUtils.java
@@ -16,7 +16,8 @@ import java.util.List;
 public class SaveUtils {
     
     static String deriveSaveDirectoryPath(String saveName){
-        return "./saves/" + saveName;
+        String path = "/home/satellite/temp/saves/" + saveName;
+        return path;
     }
     
     /**
@@ -30,7 +31,7 @@ public class SaveUtils {
         if(FileUtils.checkFileExists(dirPath)){
             return false;
         }
-        //create dir
+        // create dir
         if(!FileUtils.createDirectory(dirPath)){
             //we for some unknown reason, couldn't make the save dir
             return false;
@@ -61,8 +62,10 @@ public class SaveUtils {
         String dirPath = deriveSaveDirectoryPath(saveName);
         String dbFilePath = FileUtils.sanitizeFilePath(dirPath) + "/central.db";
         Globals.dbController.connect(dbFilePath);
-        Globals.serverTerrainManager.load(saveName);
-        Globals.serverWorldData = FileUtils.loadObjectFromSavePath(saveName, "world.json", ServerWorldData.class);
+        if(!saveName.equals("arena")){
+            Globals.serverTerrainManager.load(saveName);
+            Globals.serverWorldData = FileUtils.loadObjectFromSavePath(saveName, "world.json", ServerWorldData.class);
+        }
         return true;
     }
     
diff --git a/src/main/java/electrosphere/game/server/structure/virtual/StructureManager.java b/src/main/java/electrosphere/game/server/structure/virtual/StructureManager.java
index 8ed5afb4..483c5a4d 100644
--- a/src/main/java/electrosphere/game/server/structure/virtual/StructureManager.java
+++ b/src/main/java/electrosphere/game/server/structure/virtual/StructureManager.java
@@ -2,6 +2,7 @@ package electrosphere.game.server.structure.virtual;
 
 import com.google.gson.Gson;
 import electrosphere.game.server.db.DatabaseResult;
+import electrosphere.game.server.db.DatabaseResultRow;
 import electrosphere.logger.LoggerInterface;
 import electrosphere.main.Globals;
 import java.sql.ResultSet;
@@ -29,24 +30,19 @@ public class StructureManager {
     public static Structure createStructure(int worldX, int worldY, float localX, float localY, String type){
         structIDIterator++;
         Structure rVal = new Structure(worldX, worldY, localX, localY, type);
-        Globals.dbController.executeStatement("INSERT INTO structWorldPositions (structID,posX,posY) VALUES (" + structIDIterator + "," + worldX + "," + worldY + ");");
-        Globals.dbController.executeStatement("INSERT INTO structData(structID,propName,propValue) VALUES(" + structIDIterator + ",'localX','" + localX + "');");
-        Globals.dbController.executeStatement("INSERT INTO structData(structID,propName,propValue) VALUES(" + structIDIterator + ",'localY','" + localY + "');");
+        Globals.dbController.executePreparedStatement("INSERT INTO structWorldPositions (structID,posX,posY) VALUES (?,?,?);",structIDIterator,worldX,worldY);
+        Globals.dbController.executePreparedStatement("INSERT INTO structData(structID,propName,propValue) VALUES(?,'localX','?');",structIDIterator,localX);
+        Globals.dbController.executePreparedStatement("INSERT INTO structData(structID,propName,propValue) VALUES(?,'localY','?');",structIDIterator,localY);
         return rVal;
     }
     
     public static List getStructuresInChunk(int worldX, int worldY){
         List rVal = new LinkedList();
-        DatabaseResult result = Globals.dbController.executeStatement("SELECT * FROM structWorldPositions WHERE posX = " + worldX + " AND posY = " + worldY + ";");
+        DatabaseResult result = Globals.dbController.executePreparedQuery("SELECT * FROM structWorldPositions WHERE posX = ? AND posY = ?;",worldX,worldY);
         List returnedIDs = new LinkedList();
-        if(result.hasResultSet()){
-            ResultSet positionSet = result.getResultSet();
-            try {
-                while(positionSet.next()){
-                    returnedIDs.add(positionSet.getInt("structID"));
-                }
-            } catch (SQLException ex) {
-                LoggerInterface.loggerEngine.ERROR("Error looping through positions returned in StructureManager.getStructuresInChunk", ex);
+        if(result.success() && result.hasResult()){
+            for(DatabaseResultRow row : result){
+                returnedIDs.add(row.getAsInteger("structID"));
             }
         }
         if(returnedIDs.size() > 0){
@@ -55,17 +51,11 @@ public class StructureManager {
                 ids = ids + ID + ",";
             }
             ids = ids.substring(0, ids.length() - 1);
-            result = Globals.dbController.executeStatement("SELECT * FROM structData WHERE structID IN (" + ids + ");");
-            if(result.success() && result.hasResultSet()){
-                ResultSet rs = result.getResultSet();
-                try {
-                    while(rs.next()){
-                        String rawData = rs.getString("dataVal");
-                        Structure newStruct = serializer.fromJson(rawData, Structure.class);
-                        rVal.add(newStruct);
-                    }
-                } catch (SQLException ex) {
-                    LoggerInterface.loggerEngine.ERROR("Error looping through structures returned in StructureManager.getStructuresInChunk", ex);
+            result = Globals.dbController.executePreparedQuery("SELECT * FROM structData WHERE structID IN (?);",ids);
+            if(result.success() && result.hasResult()){
+                for(DatabaseResultRow row : result){
+                    Structure newStruct = serializer.fromJson(row.getAsString("dataVal"), Structure.class);
+                    rVal.add(newStruct);
                 }
             }
         }
diff --git a/src/main/java/electrosphere/logger/Logger.java b/src/main/java/electrosphere/logger/Logger.java
index 5479a4f6..2a07265a 100644
--- a/src/main/java/electrosphere/logger/Logger.java
+++ b/src/main/java/electrosphere/logger/Logger.java
@@ -40,6 +40,7 @@ public class Logger {
     public void ERROR(String message, Exception e){
         if(level == LogLevel.DEBUG || level == LogLevel.INFO || level == LogLevel.WARNING || level == LogLevel.ERROR){
             System.out.println(message);
+            e.printStackTrace();
         }
     }
 }
diff --git a/src/main/java/electrosphere/logger/LoggerInterface.java b/src/main/java/electrosphere/logger/LoggerInterface.java
index a0de4784..a6e4b24d 100644
--- a/src/main/java/electrosphere/logger/LoggerInterface.java
+++ b/src/main/java/electrosphere/logger/LoggerInterface.java
@@ -16,6 +16,7 @@ public class LoggerInterface {
     public static Logger loggerRenderer;
     public static Logger loggerEngine;
     public static Logger loggerStartup;
+    public static Logger loggerAuth;
     
     public static void initLoggers(){
         loggerStartup = new Logger(LogLevel.WARNING);
@@ -24,6 +25,7 @@ public class LoggerInterface {
         loggerGameLogic = new Logger(LogLevel.WARNING);
         loggerRenderer = new Logger(LogLevel.WARNING);
         loggerEngine = new Logger(LogLevel.WARNING);
+        loggerAuth = new Logger(LogLevel.INFO);
         loggerStartup.INFO("Initialized loggers");
     }
 }
diff --git a/src/main/java/electrosphere/main/Globals.java b/src/main/java/electrosphere/main/Globals.java
index 2a8503cd..5bbea10a 100644
--- a/src/main/java/electrosphere/main/Globals.java
+++ b/src/main/java/electrosphere/main/Globals.java
@@ -176,6 +176,8 @@ public class Globals {
     //
     public static PlayerManager playerManager;
     public static Player clientPlayer;
+    public static String clientUsername;
+    public static String clientPassword;
     
     //
     //Generic OpenGL Statements
diff --git a/src/main/java/electrosphere/main/Main.java b/src/main/java/electrosphere/main/Main.java
index 9b3a6e26..65dd897c 100644
--- a/src/main/java/electrosphere/main/Main.java
+++ b/src/main/java/electrosphere/main/Main.java
@@ -4,6 +4,7 @@ import com.google.gson.Gson;
 import electrosphere.audio.AudioEngine;
 import electrosphere.audio.AudioSource;
 import electrosphere.audio.AudioUtils;
+import electrosphere.auth.AuthenticationManager;
 import electrosphere.controls.ControlHandler;
 import electrosphere.entity.types.creature.CreatureUtils;
 import electrosphere.renderer.Material;
@@ -48,9 +49,14 @@ import java.io.IOException;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.StandardOpenOption;
+import java.security.Provider;
+import java.security.Security;
 import java.util.Scanner;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+
+import javax.crypto.Cipher;
+
 import org.joml.Vector3d;
 
 
@@ -107,6 +113,16 @@ public class Main {
         
         //init global variables
         Globals.initGlobals();
+
+        // if(1==1){
+        //     SaveUtils.loadSave("arena");
+        //     Globals.authenticationManager = new AuthenticationManager();
+        //     String rawPass = "testpassword";
+        //     String hashedPassword = AuthenticationManager.getHashedString(rawPass);
+        //     boolean authed = Globals.authenticationManager.authenticate("testuser", hashedPassword);
+        //     System.out.println("Authenticated: " + authed);
+        //     System.exit(0);
+        // }
         
         //world gen testing
         //gen terrain
diff --git a/src/main/java/electrosphere/menu/MenuGenerators.java b/src/main/java/electrosphere/menu/MenuGenerators.java
index 6855e517..36437218 100644
--- a/src/main/java/electrosphere/menu/MenuGenerators.java
+++ b/src/main/java/electrosphere/menu/MenuGenerators.java
@@ -102,14 +102,12 @@ public class MenuGenerators {
         arenaButton.addChild(arenaLabel);
         rVal.addChild(arenaButton);
         arenaButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
-            LoadingThread clientThread = new LoadingThread(LoadingThread.LOAD_CHARACTER_SERVER);
-            Globals.loadingThreadsList.add(clientThread);
             LoadingThread serverThread = new LoadingThread(LoadingThread.LOAD_ARENA);
             Globals.loadingThreadsList.add(serverThread);
             Globals.RUN_CLIENT = true;
             Globals.RUN_SERVER = true;
-            clientThread.start();
             serverThread.start();
+            WindowUtils.replaceMainMenuContents(MenuGeneratorsArena.createArenaHostLoginMenu());
             return false;
         }});
 
@@ -455,7 +453,7 @@ public class MenuGenerators {
                     //clear ui
                     WindowUtils.cleanItemDraggingWindow();
                     String sourceWindowId = WindowStrings.WINDOW_CHARACTER;
-                    WindowUtils.replaceWindow(sourceWindowId,MenuGenerators.createCharacterMenu(inventory));
+                    WindowUtils.replaceWindow(sourceWindowId,MenuGenerators.createCharacterInventoryMenu(inventory));
                     //null globals
                     Globals.dragSourceInventory = null;
                     Globals.draggedItem = null;
@@ -924,7 +922,7 @@ public class MenuGenerators {
                         WindowUtils.cleanItemDraggingWindow();
                         //rerender both inventories
                         //re-render inventory
-                        WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, MenuGenerators.createCharacterMenu(sourceInventory));
+                        WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, MenuGenerators.createCharacterInventoryMenu(sourceInventory));
                         //re-render inventory
                         WindowUtils.replaceWindow(WindowUtils.getInventoryWindowID(inventory.getId()), MenuGenerators.createNaturalInventoryMenu(inventory));
                     }
@@ -953,7 +951,7 @@ public class MenuGenerators {
     }
 
 
-    public static Window createCharacterMenu(RelationalInventoryState inventory){
+    public static Window createCharacterInventoryMenu(RelationalInventoryState inventory){
         // int screenTop = Globals.WINDOW_HEIGHT - 150;
         int width = 500;
         int height = 500;
@@ -987,7 +985,7 @@ public class MenuGenerators {
                     WindowUtils.cleanItemDraggingWindow();
                     //rerender both inventories
                     //re-render inventory
-                    WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, MenuGenerators.createCharacterMenu(inventory));
+                    WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, MenuGenerators.createCharacterInventoryMenu(inventory));
                     //re-render inventory
                     WindowUtils.replaceWindow(WindowUtils.getInventoryWindowID(sourceInventory.getId()), MenuGenerators.createNaturalInventoryMenu(sourceInventory));
                 }
@@ -1088,7 +1086,7 @@ public class MenuGenerators {
                         WindowUtils.cleanItemDraggingWindow();
                         //rerender both inventories
                         //re-render inventory
-                        WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, MenuGenerators.createCharacterMenu(inventory));
+                        WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, MenuGenerators.createCharacterInventoryMenu(inventory));
                         //re-render inventory
                         WindowUtils.replaceWindow(WindowUtils.getInventoryWindowID(sourceInventory.getId()), MenuGenerators.createNaturalInventoryMenu(sourceInventory));
                     }
diff --git a/src/main/java/electrosphere/menu/MenuGeneratorsArena.java b/src/main/java/electrosphere/menu/MenuGeneratorsArena.java
new file mode 100644
index 00000000..4cca6b59
--- /dev/null
+++ b/src/main/java/electrosphere/menu/MenuGeneratorsArena.java
@@ -0,0 +1,70 @@
+package electrosphere.menu;
+
+import electrosphere.auth.AuthenticationManager;
+import electrosphere.engine.LoadingThread;
+import electrosphere.main.Globals;
+import electrosphere.net.NetUtils;
+import electrosphere.renderer.ui.ClickableElement;
+import electrosphere.renderer.ui.Element;
+import electrosphere.renderer.ui.elements.Button;
+import electrosphere.renderer.ui.elements.Label;
+import electrosphere.renderer.ui.elements.TextInput;
+import electrosphere.renderer.ui.events.ClickEvent;
+import electrosphere.renderer.ui.form.FormElement;
+
+public class MenuGeneratorsArena {
+    
+    public static Element createArenaHostLoginMenu(){
+        FormElement rVal = new FormElement();
+        int screenTop = 150;
+        
+        //label (address)
+        Label usernameLabel = new Label(100,screenTop + 50,1.0f);
+        usernameLabel.setText("Username");
+        rVal.addChild(usernameLabel);
+
+        //text entry (address)
+        TextInput usernameInput = new TextInput(100,screenTop + 125,1.0f);
+        usernameInput.setText("");
+        rVal.addChild(usernameInput);
+
+        //label (port)
+        Label passwordLabel = new Label(100,screenTop + 200,1.0f);
+        passwordLabel.setText("Password");
+        rVal.addChild(passwordLabel);
+
+        //text entry (port)
+        TextInput passwordInput = new TextInput(100,screenTop + 275,1.0f);
+        passwordInput.setText("");
+        rVal.addChild(passwordInput);
+
+        //button (connect)
+        Button connectButton = new Button();
+        Label connectLabel = new Label(100,screenTop + 350,1.0f);
+        connectLabel.setText("Login");
+        connectButton.addChild(connectLabel);
+        rVal.addChild(connectButton);
+        connectButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
+            Globals.clientUsername = usernameInput.getText();
+            Globals.clientPassword = AuthenticationManager.getHashedString(passwordInput.getText());
+            LoadingThread clientThread = new LoadingThread(LoadingThread.LOAD_CHARACTER_SERVER);
+            Globals.loadingThreadsList.add(clientThread);
+            clientThread.start();
+            return false;
+        }});
+
+        //button (back)
+        // Button backButton = new Button();
+        // Label backLabel = new Label(100,screenTop + 425,1.0f);
+        // backLabel.setText("Back");
+        // backButton.addChild(backLabel);
+        // rVal.addChild(backButton);
+        // backButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
+        //     WindowUtils.replaceMainMenuContents(MenuGenerators.createMultiplayerMenu());
+        //     return false;
+        // }});
+
+        return rVal;
+    }
+
+}
diff --git a/src/main/java/electrosphere/net/client/ClientNetworking.java b/src/main/java/electrosphere/net/client/ClientNetworking.java
index 798d5f2f..f69e9c87 100644
--- a/src/main/java/electrosphere/net/client/ClientNetworking.java
+++ b/src/main/java/electrosphere/net/client/ClientNetworking.java
@@ -26,8 +26,6 @@ import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import javax.crypto.spec.SecretKeySpec;
-import org.apache.commons.crypto.stream.CryptoInputStream;
-import org.apache.commons.crypto.stream.CryptoOutputStream;
 
 /**
  *
@@ -94,7 +92,7 @@ public class ClientNetworking implements Runnable{
             }
             if(connectionAttempts > MAX_CONNECTION_ATTEMPTS){
                 LoggerInterface.loggerNetworking.ERROR("Max client connection attempts!", new Exception());
-                System.exit(1);
+                // System.exit(1);
             }
         }
 
diff --git a/src/main/java/electrosphere/net/client/protocol/AuthProtocol.java b/src/main/java/electrosphere/net/client/protocol/AuthProtocol.java
index 21f09289..a799541b 100644
--- a/src/main/java/electrosphere/net/client/protocol/AuthProtocol.java
+++ b/src/main/java/electrosphere/net/client/protocol/AuthProtocol.java
@@ -14,15 +14,19 @@ public class AuthProtocol {
             case AUTHREQUEST:
                 //Try login
                 //TODO: actually get user/pass
-                Globals.clientConnection.queueOutgoingMessage(AuthMessage.constructAuthDetailsMessage("myuser","mypass"));
+                Globals.clientConnection.queueOutgoingMessage(AuthMessage.constructAuthDetailsMessage(Globals.clientUsername,Globals.clientPassword));
                 break;
             case AUTHSUCCESS:
+                //clean password hash from memory
+                Globals.clientPassword = "";
                 //request playable races
                 Globals.clientConnection.queueOutgoingMessage(LoreMessage.constructRequestRacesMessage());
+                //log that we succeeded
+                LoggerInterface.loggerAuth.INFO("Successfully logged in");
                 break;
             case AUTHFAILURE:
                 //TODO: handle better
-                LoggerInterface.loggerEngine.ERROR("Auth failure",new Exception("Auth failure"));
+                LoggerInterface.loggerAuth.ERROR("Auth failure",new Exception("Auth failure"));
                 break;
             //ignore stack
             case AUTHDETAILS:
diff --git a/src/main/java/electrosphere/net/server/Server.java b/src/main/java/electrosphere/net/server/Server.java
index 95deb960..4b5b76cd 100644
--- a/src/main/java/electrosphere/net/server/Server.java
+++ b/src/main/java/electrosphere/net/server/Server.java
@@ -1,5 +1,6 @@
 package electrosphere.net.server;
 
+import electrosphere.game.server.saves.SaveUtils;
 import electrosphere.main.Globals;
 import electrosphere.main.Main;
 import electrosphere.net.NetUtils;
diff --git a/src/main/java/electrosphere/net/server/ServerConnectionHandler.java b/src/main/java/electrosphere/net/server/ServerConnectionHandler.java
index 4627c5a4..da72f661 100644
--- a/src/main/java/electrosphere/net/server/ServerConnectionHandler.java
+++ b/src/main/java/electrosphere/net/server/ServerConnectionHandler.java
@@ -35,8 +35,6 @@ import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import javax.crypto.spec.SecretKeySpec;
-import org.apache.commons.crypto.stream.CryptoInputStream;
-import org.apache.commons.crypto.stream.CryptoOutputStream;
 import org.joml.Vector3f;
 
 /**
diff --git a/src/main/java/electrosphere/util/FileUtils.java b/src/main/java/electrosphere/util/FileUtils.java
index 24652262..2c641024 100644
--- a/src/main/java/electrosphere/util/FileUtils.java
+++ b/src/main/java/electrosphere/util/FileUtils.java
@@ -222,7 +222,7 @@ public class FileUtils {
      * @return true if directory was created, false if it was not
      */
     public static boolean createDirectory(String directoryName){
-        String sanitizedPath = "." + sanitizeFilePath(directoryName);
+        String sanitizedPath = sanitizeFilePath(directoryName);
         File targetDir = new File(sanitizedPath);
         if(targetDir.exists()){
             return false;
@@ -242,6 +242,21 @@ public class FileUtils {
         }
         return rVal;
     }
+
+    public static void recursivelyDelete(String path){
+        File file = new File(path);
+        if(file.isDirectory()){
+            for(File child : file.listFiles()){
+                recursivelyDelete(child.getAbsolutePath());
+            }
+        }
+        try {
+            Files.delete(file.toPath());
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }