--- ../work/decompile-8eb82bde//net/minecraft/server/ThreadPlayerLookupUUID.java	2014-11-28 17:43:43.385707429 +0000
+++ src/main/java/net/minecraft/server/ThreadPlayerLookupUUID.java	2014-11-28 17:43:20.977707926 +0000
@@ -5,6 +5,12 @@
 import java.math.BigInteger;
 import java.util.UUID;
 
+// CraftBukkit start
+import org.bukkit.craftbukkit.util.Waitable;
+import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
+import org.bukkit.event.player.PlayerPreLoginEvent;
+// CraftBukkit end
+
 class ThreadPlayerLookupUUID extends Thread {
 
     final LoginListener a;
@@ -22,6 +28,44 @@
 
             LoginListener.a(this.a, LoginListener.a(this.a).aB().hasJoinedServer(new GameProfile((UUID) null, gameprofile.getName()), s));
             if (LoginListener.b(this.a) != null) {
+                // CraftBukkit start - fire PlayerPreLoginEvent
+                if (!this.a.networkManager.g()) {
+                    return;
+                }
+
+                String playerName = LoginListener.b(this.a).getName();
+                java.net.InetAddress address = ((java.net.InetSocketAddress) a.networkManager.getSocketAddress()).getAddress();
+                java.util.UUID uniqueId = LoginListener.b(this.a).getId();
+                final org.bukkit.craftbukkit.CraftServer server = LoginListener.a(this.a).server;
+
+                AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, uniqueId);
+                server.getPluginManager().callEvent(asyncEvent);
+
+                if (PlayerPreLoginEvent.getHandlerList().getRegisteredListeners().length != 0) {
+                    final PlayerPreLoginEvent event = new PlayerPreLoginEvent(playerName, address, uniqueId);
+                    if (asyncEvent.getResult() != PlayerPreLoginEvent.Result.ALLOWED) {
+                        event.disallow(asyncEvent.getResult(), asyncEvent.getKickMessage());
+                    }
+                    Waitable<PlayerPreLoginEvent.Result> waitable = new Waitable<PlayerPreLoginEvent.Result>() {
+                        @Override
+                        protected PlayerPreLoginEvent.Result evaluate() {
+                            server.getPluginManager().callEvent(event);
+                            return event.getResult();
+                        }};
+
+                    LoginListener.a(this.a).processQueue.add(waitable);
+                    if (waitable.get() != PlayerPreLoginEvent.Result.ALLOWED) {
+                        this.a.disconnect(event.getKickMessage());
+                        return;
+                    }
+                } else {
+                    if (asyncEvent.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
+                        this.a.disconnect(asyncEvent.getKickMessage());
+                        return;
+                    }
+                }
+                // CraftBukkit end
+        
                 LoginListener.e().info("UUID of player " + LoginListener.b(this.a).getName() + " is " + LoginListener.b(this.a).getId());
                 LoginListener.a(this.a, EnumProtocolState.READY_TO_ACCEPT);
             } else if (LoginListener.a(this.a).S()) {
@@ -41,6 +85,11 @@
                 this.a.disconnect("Authentication servers are down. Please try again later, sorry!");
                 LoginListener.e().error("Couldn\'t verify username because servers are unavailable");
             }
+            // CraftBukkit start - catch all exceptions
+        } catch (Exception exception) {
+            this.a.disconnect("Failed to verify username!");
+            LoginListener.a(this.a).server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + LoginListener.a(this.a).getName(), exception);
+            // CraftBukkit end
         }
 
     }