diff --git a/src/main/java/net/knarcraft/stargate/Gate.java b/src/main/java/net/knarcraft/stargate/Gate.java
index 84c2681..83ec460 100644
--- a/src/main/java/net/knarcraft/stargate/Gate.java
+++ b/src/main/java/net/knarcraft/stargate/Gate.java
@@ -1,5 +1,6 @@
 package net.knarcraft.stargate;
 
+import net.knarcraft.stargate.utility.MaterialHelper;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
 
diff --git a/src/main/java/net/knarcraft/stargate/Portal.java b/src/main/java/net/knarcraft/stargate/Portal.java
index c6f665d..9fbb522 100644
--- a/src/main/java/net/knarcraft/stargate/Portal.java
+++ b/src/main/java/net/knarcraft/stargate/Portal.java
@@ -1290,12 +1290,11 @@ public class Portal {
                 String wName = portal.world.getName();
                 if (!wName.equalsIgnoreCase(world.getName())) continue;
                 StringBuilder builder = new StringBuilder();
-                BlockLocation sign = portal.id;
                 BlockLocation button = portal.button;
 
                 builder.append(portal.name);
                 builder.append(':');
-                builder.append(sign.toString());
+                builder.append(portal.id.toString());
                 builder.append(':');
                 builder.append((button != null) ? button.toString() : "");
                 builder.append(':');
@@ -1515,10 +1514,9 @@ public class Portal {
         } else if (!name.equalsIgnoreCase(other.name))
             return false;
         if (network == null) {
-            if (other.network != null)
-                return false;
-        } else if (!network.equalsIgnoreCase(other.network))
-            return false;
-        return true;
+            return other.network == null;
+        } else {
+            return network.equalsIgnoreCase(other.network);
+        }
     }
 }
diff --git a/src/main/java/net/knarcraft/stargate/Stargate.java b/src/main/java/net/knarcraft/stargate/Stargate.java
index 01ceb9e..4d3a0b5 100644
--- a/src/main/java/net/knarcraft/stargate/Stargate.java
+++ b/src/main/java/net/knarcraft/stargate/Stargate.java
@@ -1,38 +1,24 @@
 package net.knarcraft.stargate;
 
 import net.knarcraft.stargate.event.StargateAccessEvent;
-import net.knarcraft.stargate.event.StargateDestroyEvent;
+import net.knarcraft.stargate.listener.BlockEventListener;
+import net.knarcraft.stargate.listener.BungeeCordListener;
+import net.knarcraft.stargate.listener.EntityEventListener;
+import net.knarcraft.stargate.listener.PlayerEventsListener;
+import net.knarcraft.stargate.listener.PluginEventListener;
+import net.knarcraft.stargate.listener.VehicleEventListener;
+import net.knarcraft.stargate.listener.WorldEventListener;
+import net.knarcraft.stargate.thread.BlockPopulatorThread;
+import net.knarcraft.stargate.thread.StarGateThread;
 import org.bukkit.Bukkit;
 import org.bukkit.ChatColor;
-import org.bukkit.Material;
 import org.bukkit.Server;
 import org.bukkit.World;
-import org.bukkit.block.Block;
-import org.bukkit.block.EndGateway;
 import org.bukkit.block.Sign;
-import org.bukkit.block.data.Orientable;
-import org.bukkit.block.data.type.WallSign;
 import org.bukkit.command.Command;
 import org.bukkit.command.CommandSender;
 import org.bukkit.configuration.file.FileConfiguration;
-import org.bukkit.entity.Entity;
 import org.bukkit.entity.Player;
-import org.bukkit.entity.Vehicle;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-import org.bukkit.event.Listener;
-import org.bukkit.event.block.BlockBreakEvent;
-import org.bukkit.event.block.BlockFromToEvent;
-import org.bukkit.event.block.BlockPhysicsEvent;
-import org.bukkit.event.block.BlockPistonExtendEvent;
-import org.bukkit.event.block.BlockPistonRetractEvent;
-import org.bukkit.event.block.SignChangeEvent;
-import org.bukkit.event.entity.EntityExplodeEvent;
-import org.bukkit.event.server.PluginDisableEvent;
-import org.bukkit.event.server.PluginEnableEvent;
-import org.bukkit.event.vehicle.VehicleMoveEvent;
-import org.bukkit.event.world.WorldLoadEvent;
-import org.bukkit.event.world.WorldUnloadEvent;
 import org.bukkit.plugin.Plugin;
 import org.bukkit.plugin.PluginDescriptionFile;
 import org.bukkit.plugin.PluginManager;
@@ -43,7 +29,6 @@ import java.io.File;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 import java.util.Queue;
 import java.util.UUID;
@@ -86,6 +71,7 @@ public class Stargate extends JavaPlugin {
     private static String gateFolder;
     private static String langFolder;
     private static String defNetwork = "central";
+
     private static boolean destroyExplosion = false;
     public static int maxGates = 0;
     private static String langName = "en";
@@ -106,7 +92,7 @@ public class Stargate extends JavaPlugin {
     public static boolean debug = false;
     public static boolean permDebug = false;
 
-    public static ConcurrentLinkedQueue<Portal> openList = new ConcurrentLinkedQueue<>();
+    public static final ConcurrentLinkedQueue<Portal> openList = new ConcurrentLinkedQueue<>();
     public static ConcurrentLinkedQueue<Portal> activeList = new ConcurrentLinkedQueue<>();
 
     // Used for populating gate open/closed material.
@@ -160,12 +146,12 @@ public class Stargate extends JavaPlugin {
 
         // Register events before loading gates to stop weird things happening.
         pm.registerEvents(new PlayerEventsListener(), this);
-        pm.registerEvents(new bListener(), this);
+        pm.registerEvents(new BlockEventListener(), this);
 
-        pm.registerEvents(new vListener(), this);
-        pm.registerEvents(new eListener(), this);
-        pm.registerEvents(new wListener(), this);
-        pm.registerEvents(new sListener(), this);
+        pm.registerEvents(new VehicleEventListener(), this);
+        pm.registerEvents(new EntityEventListener(), this);
+        pm.registerEvents(new WorldEventListener(), this);
+        pm.registerEvents(new PluginEventListener(this), this);
 
         this.loadConfig();
 
@@ -195,6 +181,10 @@ public class Stargate extends JavaPlugin {
         getServer().getScheduler().scheduleSyncRepeatingTask(this, new BlockPopulatorThread(), 0L, 1L);
     }
 
+    public static boolean destroyedByExplosion() {
+        return destroyExplosion;
+    }
+
     public static int getOpenTime() {
         return openTime;
     }
@@ -660,313 +650,6 @@ public class Stargate extends JavaPlugin {
         return input.replace(search, value);
     }
 
-    private class vListener implements Listener {
-        @EventHandler
-        public void onVehicleMove(VehicleMoveEvent event) {
-            if (!handleVehicles) return;
-            List<Entity> passengers = event.getVehicle().getPassengers();
-            Vehicle vehicle = event.getVehicle();
-
-            Portal portal = Portal.getByEntrance(event.getTo());
-            if (portal == null || !portal.isOpen()) return;
-
-            // We don't support vehicles in Bungee portals
-            if (portal.isBungee()) return;
-
-            if (!passengers.isEmpty() && passengers.get(0) instanceof Player) {
-				/*
-				Player player = (Player) passengers.get(0);
-				if (!portal.isOpenFor(player)) {
-					stargate.sendMessage(player, stargate.getString("denyMsg"));
-					return;
-				}
-				
-				Portal dest = portal.getDestination(player);
-				if (dest == null) return;
-				boolean deny = false;
-				// Check if player has access to this network
-				if (!canAccessNetwork(player, portal.getNetwork())) {
-					deny = true;
-				}
-				
-				// Check if player has access to destination world
-				if (!canAccessWorld(player, dest.getWorld().getName())) {
-					deny = true;
-				}
-				
-				if (!canAccessPortal(player, portal, deny)) {
-					stargate.sendMessage(player, stargate.getString("denyMsg"));
-					portal.close(false);
-					return;
-				}
-				
-				int cost = stargate.getUseCost(player, portal, dest);
-				if (cost > 0) {
-					boolean success;
-					if(portal.getGate().getToOwner()) {
-						if(portal.getOwnerUUID() == null) {
-							success = stargate.chargePlayer(player, portal.getOwnerUUID(), cost);
-						} else {
-							success = stargate.chargePlayer(player, portal.getOwnerName(), cost);
-						}
-					} else {
-						success = stargate.chargePlayer(player, cost);
-					}
-					if(!success) {
-						// Insufficient Funds
-						stargate.sendMessage(player, stargate.getString("inFunds"));
-						portal.close(false);
-						return;
-					}
-					String deductMsg = stargate.getString("ecoDeduct");
-					deductMsg = stargate.replaceVars(deductMsg, new String[] {"%cost%", "%portal%"}, new String[] {EconomyHandler.format(cost), portal.getName()});
-					sendMessage(player, deductMsg, false);
-					if (portal.getGate().getToOwner()) {
-						Player p;
-						if(portal.getOwnerUUID() != null) {
-							p = server.getPlayer(portal.getOwnerUUID());
-						} else {
-							p = server.getPlayer(portal.getOwnerName());
-						}
-						if (p != null) {
-							String obtainedMsg = stargate.getString("ecoObtain");
-							obtainedMsg = stargate.replaceVars(obtainedMsg, new String[] {"%cost%", "%portal%"}, new String[] {EconomyHandler.format(cost), portal.getName()});
-							stargate.sendMessage(p, obtainedMsg, false);
-						}
-					}
-				}
-				
-				stargate.sendMessage(player, stargate.getString("teleportMsg"), false);
-				dest.teleport(vehicle);
-				portal.close(false);
-				 */
-            } else {
-                Portal dest = portal.getDestination();
-                if (dest == null) return;
-                dest.teleport(vehicle);
-            }
-        }
-    }
-
-
-
-    private class bListener implements Listener {
-        @EventHandler
-        public void onSignChange(SignChangeEvent event) {
-            if (event.isCancelled()) {
-                return;
-            }
-            Player player = event.getPlayer();
-            Block block = event.getBlock();
-            if (!(block.getBlockData() instanceof WallSign)) {
-                return;
-            }
-
-            final Portal portal = Portal.createPortal(event, player);
-            // Not creating a gate, just placing a sign
-            if (portal == null) {
-                return;
-            }
-
-            Stargate.sendMessage(player, Stargate.getString("createMsg"), false);
-            Stargate.debug("onSignChange", "Initialized stargate: " + portal.getName());
-            Stargate.server.getScheduler().scheduleSyncDelayedTask(stargate, new Runnable() {
-                public void run() {
-                    portal.drawSign();
-                }
-            }, 1);
-        }
-
-        // Switch to HIGHEST priority so as to come after block protection plugins (Hopefully)
-        @EventHandler(priority = EventPriority.HIGHEST)
-        public void onBlockBreak(BlockBreakEvent event) {
-            if (event.isCancelled()) return;
-            Block block = event.getBlock();
-            Player player = event.getPlayer();
-
-            Portal portal = Portal.getByBlock(block);
-            if (portal == null && protectEntrance)
-                portal = Portal.getByEntrance(block);
-            if (portal == null) return;
-
-            boolean deny = false;
-            String denyMsg = "";
-
-            if (!Stargate.canDestroy(player, portal)) {
-                denyMsg = "Permission Denied"; // TODO: Change to stargate.getString()
-                deny = true;
-                Stargate.log.info(Stargate.getString("prefix") + player.getName() + " tried to destroy gate");
-            }
-
-            int cost = Stargate.getDestroyCost(player, portal.getGate());
-
-            StargateDestroyEvent dEvent = new StargateDestroyEvent(portal, player, deny, denyMsg, cost);
-            Stargate.server.getPluginManager().callEvent(dEvent);
-            if (dEvent.isCancelled()) {
-                event.setCancelled(true);
-                return;
-            }
-            if (dEvent.getDeny()) {
-                Stargate.sendMessage(player, dEvent.getDenyReason());
-                event.setCancelled(true);
-                return;
-            }
-
-            cost = dEvent.getCost();
-
-            if (cost != 0) {
-                if (!Stargate.chargePlayer(player, cost)) {
-                    Stargate.debug("onBlockBreak", "Insufficient Funds");
-                    Stargate.sendMessage(player, Stargate.getString("inFunds"));
-                    event.setCancelled(true);
-                    return;
-                }
-
-                if (cost > 0) {
-                    String deductMsg = Stargate.getString("ecoDeduct");
-                    deductMsg = Stargate.replaceVars(deductMsg, new String[]{"%cost%", "%portal%"}, new String[]{EconomyHandler.format(cost), portal.getName()});
-                    sendMessage(player, deductMsg, false);
-                } else if (cost < 0) {
-                    String refundMsg = Stargate.getString("ecoRefund");
-                    refundMsg = Stargate.replaceVars(refundMsg, new String[]{"%cost%", "%portal%"}, new String[]{EconomyHandler.format(-cost), portal.getName()});
-                    sendMessage(player, refundMsg, false);
-                }
-            }
-
-            portal.unregister(true);
-            Stargate.sendMessage(player, Stargate.getString("destroyMsg"), false);
-        }
-
-        @EventHandler
-        public void onBlockPhysics(BlockPhysicsEvent event) {
-            Block block = event.getBlock();
-            Portal portal = null;
-
-            // Handle keeping portal material and buttons around
-            if (block.getType() == Material.NETHER_PORTAL) {
-                portal = Portal.getByEntrance(block);
-            } else if (MaterialHelper.isButtonCompatible(block.getType())) {
-                portal = Portal.getByControl(block);
-            }
-            if (portal != null) event.setCancelled(true);
-        }
-
-        @EventHandler
-        public void onBlockFromTo(BlockFromToEvent event) {
-            Portal portal = Portal.getByEntrance(event.getBlock());
-
-            if (portal != null) {
-                event.setCancelled((event.getBlock().getY() == event.getToBlock().getY()));
-            }
-        }
-
-        @EventHandler
-        public void onPistonExtend(BlockPistonExtendEvent event) {
-            for (Block block : event.getBlocks()) {
-                Portal portal = Portal.getByBlock(block);
-                if (portal != null) {
-                    event.setCancelled(true);
-                    return;
-                }
-            }
-        }
-
-        @EventHandler
-        public void onPistonRetract(BlockPistonRetractEvent event) {
-            if (!event.isSticky()) return;
-            for (Block block : event.getBlocks()) {
-                Portal portal = Portal.getByBlock(block);
-                if (portal != null) {
-                    event.setCancelled(true);
-                    return;
-                }
-            }
-        }
-    }
-
-    private class wListener implements Listener {
-        @EventHandler
-        public void onWorldLoad(WorldLoadEvent event) {
-            if (!managedWorlds.contains(event.getWorld().getName())
-                    && Portal.loadAllGates(event.getWorld())) {
-                managedWorlds.add(event.getWorld().getName());
-            }
-        }
-
-        // We need to reload all gates on world unload, boo
-        @EventHandler
-        public void onWorldUnload(WorldUnloadEvent event) {
-            Stargate.debug("onWorldUnload", "Reloading all Stargates");
-            World w = event.getWorld();
-            if (managedWorlds.contains(w.getName())) {
-                managedWorlds.remove(w.getName());
-                Portal.clearGates();
-                for (World world : server.getWorlds()) {
-                    if (managedWorlds.contains(world.getName())) {
-                        Portal.loadAllGates(world);
-                    }
-                }
-            }
-        }
-    }
-
-    private class eListener implements Listener {
-        @EventHandler
-        public void onEntityExplode(EntityExplodeEvent event) {
-            if (event.isCancelled()) return;
-            for (Block b : event.blockList()) {
-                Portal portal = Portal.getByBlock(b);
-                if (portal == null) continue;
-                if (destroyExplosion) {
-                    portal.unregister(true);
-                } else {
-                    event.setCancelled(true);
-                    break;
-                }
-            }
-        }
-    }
-
-    private class sListener implements Listener {
-        @EventHandler
-        public void onPluginEnable(PluginEnableEvent event) {
-            if (EconomyHandler.setupEconomy(getServer().getPluginManager())) {
-                String vaultVersion = EconomyHandler.vault.getDescription().getVersion();
-                log.info(Stargate.getString("prefix") +
-                        replaceVars(Stargate.getString("vaultLoaded"), "%version%", vaultVersion));
-            }
-        }
-
-        @EventHandler
-        public void onPluginDisable(PluginDisableEvent event) {
-            if (event.getPlugin().equals(EconomyHandler.vault)) {
-                log.info(Stargate.getString("prefix") + "Vault plugin lost.");
-            }
-        }
-    }
-
-    private class BlockPopulatorThread implements Runnable {
-        public void run() {
-            long sTime = System.nanoTime();
-            while (System.nanoTime() - sTime < 25000000) {
-                BloxPopulator b = Stargate.blockPopulatorQueue.poll();
-                if (b == null) return;
-                Block blk = b.getBlockLocation().getBlock();
-                blk.setType(b.getMat(), false);
-                if (b.getMat() == Material.END_GATEWAY && blk.getWorld().getEnvironment() == World.Environment.THE_END) {
-                    // force a location to prevent exit gateway generation
-                    EndGateway gateway = (EndGateway) blk.getState();
-                    gateway.setExitLocation(blk.getWorld().getSpawnLocation());
-                    gateway.setExactTeleport(true);
-                    gateway.update(false, false);
-                } else if (b.getAxis() != null) {
-                    Orientable orientable = (Orientable) blk.getBlockData();
-                    orientable.setAxis(b.getAxis());
-                    blk.setBlockData(orientable);
-                }
-            }
-        }
-    }
 
     @Override
     public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
diff --git a/src/main/java/net/knarcraft/stargate/event/StargateEvent.java b/src/main/java/net/knarcraft/stargate/event/StargateEvent.java
index d3471da..a3a40ce 100644
--- a/src/main/java/net/knarcraft/stargate/event/StargateEvent.java
+++ b/src/main/java/net/knarcraft/stargate/event/StargateEvent.java
@@ -29,7 +29,7 @@ import org.bukkit.event.Event;
 @SuppressWarnings("unused")
 public abstract class StargateEvent extends Event implements Cancellable {
 
-    protected Portal portal;
+    protected final Portal portal;
     protected boolean cancelled;
 
     public StargateEvent(String event, Portal portal) {
diff --git a/src/main/java/net/knarcraft/stargate/listener/BlockEventListener.java b/src/main/java/net/knarcraft/stargate/listener/BlockEventListener.java
new file mode 100644
index 0000000..90b2703
--- /dev/null
+++ b/src/main/java/net/knarcraft/stargate/listener/BlockEventListener.java
@@ -0,0 +1,158 @@
+package net.knarcraft.stargate.listener;
+
+import net.knarcraft.stargate.EconomyHandler;
+import net.knarcraft.stargate.Portal;
+import net.knarcraft.stargate.Stargate;
+import net.knarcraft.stargate.event.StargateDestroyEvent;
+import net.knarcraft.stargate.utility.MaterialHelper;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.data.type.WallSign;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.block.BlockFromToEvent;
+import org.bukkit.event.block.BlockPhysicsEvent;
+import org.bukkit.event.block.BlockPistonEvent;
+import org.bukkit.event.block.BlockPistonExtendEvent;
+import org.bukkit.event.block.BlockPistonRetractEvent;
+import org.bukkit.event.block.SignChangeEvent;
+
+import java.util.List;
+
+public class BlockEventListener implements Listener {
+    @EventHandler
+    public void onSignChange(SignChangeEvent event) {
+        if (event.isCancelled()) {
+            return;
+        }
+        Player player = event.getPlayer();
+        Block block = event.getBlock();
+        if (!(block.getBlockData() instanceof WallSign)) {
+            return;
+        }
+
+        final Portal portal = Portal.createPortal(event, player);
+        // Not creating a gate, just placing a sign
+        if (portal == null) {
+            return;
+        }
+
+        Stargate.sendMessage(player, Stargate.getString("createMsg"), false);
+        Stargate.debug("onSignChange", "Initialized stargate: " + portal.getName());
+        Stargate.server.getScheduler().scheduleSyncDelayedTask(Stargate.stargate, () -> portal.drawSign(), 1);
+    }
+
+    // Switch to HIGHEST priority so as to come after block protection plugins (Hopefully)
+    @EventHandler(priority = EventPriority.HIGHEST)
+    public void onBlockBreak(BlockBreakEvent event) {
+        if (event.isCancelled()) return;
+        Block block = event.getBlock();
+        Player player = event.getPlayer();
+
+        Portal portal = Portal.getByBlock(block);
+        if (portal == null && Stargate.protectEntrance)
+            portal = Portal.getByEntrance(block);
+        if (portal == null) return;
+
+        boolean deny = false;
+        String denyMsg = "";
+
+        if (!Stargate.canDestroy(player, portal)) {
+            denyMsg = "Permission Denied"; // TODO: Change to stargate.getString()
+            deny = true;
+            Stargate.log.info(Stargate.getString("prefix") + player.getName() + " tried to destroy gate");
+        }
+
+        int cost = Stargate.getDestroyCost(player, portal.getGate());
+
+        StargateDestroyEvent destroyEvent = new StargateDestroyEvent(portal, player, deny, denyMsg, cost);
+        Stargate.server.getPluginManager().callEvent(destroyEvent);
+        if (destroyEvent.isCancelled()) {
+            event.setCancelled(true);
+            return;
+        }
+        if (destroyEvent.getDeny()) {
+            Stargate.sendMessage(player, destroyEvent.getDenyReason());
+            event.setCancelled(true);
+            return;
+        }
+
+        cost = destroyEvent.getCost();
+
+        if (cost != 0) {
+            if (!Stargate.chargePlayer(player, cost)) {
+                Stargate.debug("onBlockBreak", "Insufficient Funds");
+                Stargate.sendMessage(player, Stargate.getString("inFunds"));
+                event.setCancelled(true);
+                return;
+            }
+
+            if (cost > 0) {
+                String deductMsg = Stargate.getString("ecoDeduct");
+                deductMsg = Stargate.replaceVars(deductMsg, new String[]{"%cost%", "%portal%"}, new String[]{EconomyHandler.format(cost), portal.getName()});
+                Stargate.sendMessage(player, deductMsg, false);
+            } else {
+                String refundMsg = Stargate.getString("ecoRefund");
+                refundMsg = Stargate.replaceVars(refundMsg, new String[]{"%cost%", "%portal%"}, new String[]{EconomyHandler.format(-cost), portal.getName()});
+                Stargate.sendMessage(player, refundMsg, false);
+            }
+        }
+
+        portal.unregister(true);
+        Stargate.sendMessage(player, Stargate.getString("destroyMsg"), false);
+    }
+
+    @EventHandler
+    public void onBlockPhysics(BlockPhysicsEvent event) {
+        Block block = event.getBlock();
+        Portal portal = null;
+
+        // Handle keeping portal material and buttons around
+        if (block.getType() == Material.NETHER_PORTAL) {
+            portal = Portal.getByEntrance(block);
+        } else if (MaterialHelper.isButtonCompatible(block.getType())) {
+            portal = Portal.getByControl(block);
+        }
+        if (portal != null) event.setCancelled(true);
+    }
+
+    @EventHandler
+    public void onBlockFromTo(BlockFromToEvent event) {
+        Portal portal = Portal.getByEntrance(event.getBlock());
+
+        if (portal != null) {
+            event.setCancelled((event.getBlock().getY() == event.getToBlock().getY()));
+        }
+    }
+
+    @EventHandler
+    public void onPistonExtend(BlockPistonExtendEvent event) {
+        cancelPistonEvent(event, event.getBlocks());
+    }
+
+    @EventHandler
+    public void onPistonRetract(BlockPistonRetractEvent event) {
+        if (!event.isSticky()) {
+            return;
+        }
+        cancelPistonEvent(event, event.getBlocks());
+    }
+
+    /**
+     * Cancels a piston event if it would destroy a portal
+     * @param event <p>The event to cancel</p>
+     * @param blocks <p>The blocks included in the event</p>
+     */
+    private void cancelPistonEvent(BlockPistonEvent event, List<Block> blocks) {
+        for (Block block : blocks) {
+            Portal portal = Portal.getByBlock(block);
+            if (portal != null) {
+                event.setCancelled(true);
+                return;
+            }
+        }
+    }
+}
diff --git a/src/main/java/net/knarcraft/stargate/BungeeCordListener.java b/src/main/java/net/knarcraft/stargate/listener/BungeeCordListener.java
similarity index 96%
rename from src/main/java/net/knarcraft/stargate/BungeeCordListener.java
rename to src/main/java/net/knarcraft/stargate/listener/BungeeCordListener.java
index 2737a34..51be7d5 100644
--- a/src/main/java/net/knarcraft/stargate/BungeeCordListener.java
+++ b/src/main/java/net/knarcraft/stargate/listener/BungeeCordListener.java
@@ -1,5 +1,7 @@
-package net.knarcraft.stargate;
+package net.knarcraft.stargate.listener;
 
+import net.knarcraft.stargate.Portal;
+import net.knarcraft.stargate.Stargate;
 import org.bukkit.entity.Player;
 import org.bukkit.plugin.messaging.PluginMessageListener;
 
diff --git a/src/main/java/net/knarcraft/stargate/listener/EntityEventListener.java b/src/main/java/net/knarcraft/stargate/listener/EntityEventListener.java
new file mode 100644
index 0000000..a0f7759
--- /dev/null
+++ b/src/main/java/net/knarcraft/stargate/listener/EntityEventListener.java
@@ -0,0 +1,29 @@
+package net.knarcraft.stargate.listener;
+
+import net.knarcraft.stargate.Portal;
+import net.knarcraft.stargate.Stargate;
+import org.bukkit.block.Block;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityExplodeEvent;
+
+public class EntityEventListener implements Listener {
+    @EventHandler
+    public void onEntityExplode(EntityExplodeEvent event) {
+        if (event.isCancelled()) {
+            return;
+        }
+        for (Block b : event.blockList()) {
+            Portal portal = Portal.getByBlock(b);
+            if (portal == null) {
+                continue;
+            }
+            if (Stargate.destroyedByExplosion()) {
+                portal.unregister(true);
+            } else {
+                event.setCancelled(true);
+                break;
+            }
+        }
+    }
+}
diff --git a/src/main/java/net/knarcraft/stargate/PlayerEventsListener.java b/src/main/java/net/knarcraft/stargate/listener/PlayerEventsListener.java
similarity index 98%
rename from src/main/java/net/knarcraft/stargate/PlayerEventsListener.java
rename to src/main/java/net/knarcraft/stargate/listener/PlayerEventsListener.java
index 44216b5..36399b9 100644
--- a/src/main/java/net/knarcraft/stargate/PlayerEventsListener.java
+++ b/src/main/java/net/knarcraft/stargate/listener/PlayerEventsListener.java
@@ -1,5 +1,9 @@
-package net.knarcraft.stargate;
+package net.knarcraft.stargate.listener;
 
+import net.knarcraft.stargate.EconomyHandler;
+import net.knarcraft.stargate.utility.MaterialHelper;
+import net.knarcraft.stargate.Portal;
+import net.knarcraft.stargate.Stargate;
 import org.bukkit.GameMode;
 import org.bukkit.World;
 import org.bukkit.block.Block;
diff --git a/src/main/java/net/knarcraft/stargate/listener/PluginEventListener.java b/src/main/java/net/knarcraft/stargate/listener/PluginEventListener.java
new file mode 100644
index 0000000..dbf96e5
--- /dev/null
+++ b/src/main/java/net/knarcraft/stargate/listener/PluginEventListener.java
@@ -0,0 +1,32 @@
+package net.knarcraft.stargate.listener;
+
+import net.knarcraft.stargate.EconomyHandler;
+import net.knarcraft.stargate.Stargate;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.server.PluginDisableEvent;
+import org.bukkit.event.server.PluginEnableEvent;
+
+public class PluginEventListener implements Listener {
+    private final Stargate stargate;
+
+    public PluginEventListener(Stargate stargate) {
+        this.stargate = stargate;
+    }
+
+    @EventHandler
+    public void onPluginEnable(PluginEnableEvent event) {
+        if (EconomyHandler.setupEconomy(stargate.getServer().getPluginManager())) {
+            String vaultVersion = EconomyHandler.vault.getDescription().getVersion();
+            Stargate.log.info(Stargate.getString("prefix") +
+                    Stargate.replaceVars(Stargate.getString("vaultLoaded"), "%version%", vaultVersion));
+        }
+    }
+
+    @EventHandler
+    public void onPluginDisable(PluginDisableEvent event) {
+        if (event.getPlugin().equals(EconomyHandler.vault)) {
+            Stargate.log.info(Stargate.getString("prefix") + "Vault plugin lost.");
+        }
+    }
+}
diff --git a/src/main/java/net/knarcraft/stargate/listener/VehicleEventListener.java b/src/main/java/net/knarcraft/stargate/listener/VehicleEventListener.java
new file mode 100644
index 0000000..1c31b69
--- /dev/null
+++ b/src/main/java/net/knarcraft/stargate/listener/VehicleEventListener.java
@@ -0,0 +1,100 @@
+package net.knarcraft.stargate.listener;
+
+import net.knarcraft.stargate.Portal;
+import net.knarcraft.stargate.Stargate;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.Vehicle;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.vehicle.VehicleMoveEvent;
+
+import java.util.List;
+
+public class VehicleEventListener implements Listener {
+    @EventHandler
+    public void onVehicleMove(VehicleMoveEvent event) {
+        if (!Stargate.handleVehicles) return;
+        List<Entity> passengers = event.getVehicle().getPassengers();
+        Vehicle vehicle = event.getVehicle();
+
+        Portal portal = Portal.getByEntrance(event.getTo());
+        if (portal == null || !portal.isOpen()) return;
+
+        // We don't support vehicles in Bungee portals
+        if (portal.isBungee()) return;
+
+        if (!passengers.isEmpty() && passengers.get(0) instanceof Player) {
+            /*
+            Player player = (Player) passengers.get(0);
+            if (!portal.isOpenFor(player)) {
+                stargate.sendMessage(player, stargate.getString("denyMsg"));
+                return;
+            }
+
+            Portal dest = portal.getDestination(player);
+            if (dest == null) return;
+            boolean deny = false;
+            // Check if player has access to this network
+            if (!canAccessNetwork(player, portal.getNetwork())) {
+                deny = true;
+            }
+
+            // Check if player has access to destination world
+            if (!canAccessWorld(player, dest.getWorld().getName())) {
+                deny = true;
+            }
+
+            if (!canAccessPortal(player, portal, deny)) {
+                stargate.sendMessage(player, stargate.getString("denyMsg"));
+                portal.close(false);
+                return;
+            }
+
+            int cost = stargate.getUseCost(player, portal, dest);
+            if (cost > 0) {
+                boolean success;
+                if(portal.getGate().getToOwner()) {
+                    if(portal.getOwnerUUID() == null) {
+                        success = stargate.chargePlayer(player, portal.getOwnerUUID(), cost);
+                    } else {
+                        success = stargate.chargePlayer(player, portal.getOwnerName(), cost);
+                    }
+                } else {
+                    success = stargate.chargePlayer(player, cost);
+                }
+                if(!success) {
+                    // Insufficient Funds
+                    stargate.sendMessage(player, stargate.getString("inFunds"));
+                    portal.close(false);
+                    return;
+                }
+                String deductMsg = stargate.getString("ecoDeduct");
+                deductMsg = stargate.replaceVars(deductMsg, new String[] {"%cost%", "%portal%"}, new String[] {EconomyHandler.format(cost), portal.getName()});
+                sendMessage(player, deductMsg, false);
+                if (portal.getGate().getToOwner()) {
+                    Player p;
+                    if(portal.getOwnerUUID() != null) {
+                        p = server.getPlayer(portal.getOwnerUUID());
+                    } else {
+                        p = server.getPlayer(portal.getOwnerName());
+                    }
+                    if (p != null) {
+                        String obtainedMsg = stargate.getString("ecoObtain");
+                        obtainedMsg = stargate.replaceVars(obtainedMsg, new String[] {"%cost%", "%portal%"}, new String[] {EconomyHandler.format(cost), portal.getName()});
+                        stargate.sendMessage(p, obtainedMsg, false);
+                    }
+                }
+            }
+
+            stargate.sendMessage(player, stargate.getString("teleportMsg"), false);
+            dest.teleport(vehicle);
+            portal.close(false);
+             */
+        } else {
+            Portal dest = portal.getDestination();
+            if (dest == null) return;
+            dest.teleport(vehicle);
+        }
+    }
+}
diff --git a/src/main/java/net/knarcraft/stargate/listener/WorldEventListener.java b/src/main/java/net/knarcraft/stargate/listener/WorldEventListener.java
new file mode 100644
index 0000000..e7d33be
--- /dev/null
+++ b/src/main/java/net/knarcraft/stargate/listener/WorldEventListener.java
@@ -0,0 +1,35 @@
+package net.knarcraft.stargate.listener;
+
+import net.knarcraft.stargate.Portal;
+import net.knarcraft.stargate.Stargate;
+import org.bukkit.World;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.world.WorldLoadEvent;
+import org.bukkit.event.world.WorldUnloadEvent;
+
+public class WorldEventListener implements Listener {
+    @EventHandler
+    public void onWorldLoad(WorldLoadEvent event) {
+        if (!Stargate.managedWorlds.contains(event.getWorld().getName())
+                && Portal.loadAllGates(event.getWorld())) {
+            Stargate.managedWorlds.add(event.getWorld().getName());
+        }
+    }
+
+    // We need to reload all gates on world unload, boo
+    @EventHandler
+    public void onWorldUnload(WorldUnloadEvent event) {
+        Stargate.debug("onWorldUnload", "Reloading all Stargates");
+        World w = event.getWorld();
+        if (Stargate.managedWorlds.contains(w.getName())) {
+            Stargate.managedWorlds.remove(w.getName());
+            Portal.clearGates();
+            for (World world : Stargate.server.getWorlds()) {
+                if (Stargate.managedWorlds.contains(world.getName())) {
+                    Portal.loadAllGates(world);
+                }
+            }
+        }
+    }
+}
diff --git a/src/main/java/net/knarcraft/stargate/thread/BlockPopulatorThread.java b/src/main/java/net/knarcraft/stargate/thread/BlockPopulatorThread.java
new file mode 100644
index 0000000..1f620e2
--- /dev/null
+++ b/src/main/java/net/knarcraft/stargate/thread/BlockPopulatorThread.java
@@ -0,0 +1,32 @@
+package net.knarcraft.stargate.thread;
+
+import net.knarcraft.stargate.BloxPopulator;
+import net.knarcraft.stargate.Stargate;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.block.EndGateway;
+import org.bukkit.block.data.Orientable;
+
+public class BlockPopulatorThread implements Runnable {
+    public void run() {
+        long sTime = System.nanoTime();
+        while (System.nanoTime() - sTime < 25000000) {
+            BloxPopulator b = Stargate.blockPopulatorQueue.poll();
+            if (b == null) return;
+            Block blk = b.getBlockLocation().getBlock();
+            blk.setType(b.getMat(), false);
+            if (b.getMat() == Material.END_GATEWAY && blk.getWorld().getEnvironment() == World.Environment.THE_END) {
+                // force a location to prevent exit gateway generation
+                EndGateway gateway = (EndGateway) blk.getState();
+                gateway.setExitLocation(blk.getWorld().getSpawnLocation());
+                gateway.setExactTeleport(true);
+                gateway.update(false, false);
+            } else if (b.getAxis() != null) {
+                Orientable orientable = (Orientable) blk.getBlockData();
+                orientable.setAxis(b.getAxis());
+                blk.setBlockData(orientable);
+            }
+        }
+    }
+}
diff --git a/src/main/java/net/knarcraft/stargate/StarGateThread.java b/src/main/java/net/knarcraft/stargate/thread/StarGateThread.java
similarity index 90%
rename from src/main/java/net/knarcraft/stargate/StarGateThread.java
rename to src/main/java/net/knarcraft/stargate/thread/StarGateThread.java
index 516b326..bfdedec 100644
--- a/src/main/java/net/knarcraft/stargate/StarGateThread.java
+++ b/src/main/java/net/knarcraft/stargate/thread/StarGateThread.java
@@ -1,4 +1,7 @@
-package net.knarcraft.stargate;
+package net.knarcraft.stargate.thread;
+
+import net.knarcraft.stargate.Portal;
+import net.knarcraft.stargate.Stargate;
 
 import java.util.Iterator;
 
diff --git a/src/main/java/net/knarcraft/stargate/MaterialHelper.java b/src/main/java/net/knarcraft/stargate/utility/MaterialHelper.java
similarity index 94%
rename from src/main/java/net/knarcraft/stargate/MaterialHelper.java
rename to src/main/java/net/knarcraft/stargate/utility/MaterialHelper.java
index 8a2e149..83d6e5a 100644
--- a/src/main/java/net/knarcraft/stargate/MaterialHelper.java
+++ b/src/main/java/net/knarcraft/stargate/utility/MaterialHelper.java
@@ -1,4 +1,4 @@
-package net.knarcraft.stargate;
+package net.knarcraft.stargate.utility;
 
 import org.bukkit.Material;
 import org.bukkit.Tag;
@@ -6,7 +6,7 @@ import org.bukkit.Tag;
 /**
  * This class helps decide properties of materials not already present in the Spigot API
  */
-public class MaterialHelper {
+public final class MaterialHelper {
 
     /**
      * Checks whether the given material is a dead or alive wall coral