package net.glowstone.net.handler.login;

import com.flowpowered.networking.MessageHandler;
import net.glowstone.entity.meta.profile.PlayerProfile;
import net.glowstone.net.GlowSession;
import net.glowstone.net.ProxyData;
import net.glowstone.net.message.login.EncryptionKeyRequestMessage;
import net.glowstone.net.message.login.LoginStartMessage;
import net.glowstone.util.SecurityUtils;

import java.nio.charset.StandardCharsets;
import java.util.UUID;

public final class LoginStartHandler implements MessageHandler<GlowSession, LoginStartMessage> {

    @Override
    public void handle(GlowSession session, LoginStartMessage message) {
        final String name = message.getUsername();

        if (session.getServer().getOnlineMode()) {
            // Get necessary information to create our request message
            final String sessionId = session.getSessionId();
            final byte[] publicKey = SecurityUtils.generateX509Key(session.getServer().getKeyPair().getPublic()).getEncoded(); //Convert to X509 format
            final byte[] verifyToken = SecurityUtils.generateVerifyToken();

            // Set verify data on session for use in the response handler
            session.setVerifyToken(verifyToken);
            session.setVerifyUsername(name);

            // Send created request message and wait for the response
            session.send(new EncryptionKeyRequestMessage(sessionId, publicKey, verifyToken));
        } else {
            ProxyData proxy = session.getProxyData();
            if (proxy == null) {
                UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8));
                session.setPlayer(new PlayerProfile(name, uuid));
            } else {
                PlayerProfile profile = proxy.getProfile();
                session.setPlayer(profile == null ? proxy.getProfile(name) : profile);
            }
        }
    }
}

@@ -85,16 +85,51 @@
 andler;%0A
+import net.glowstone.EventFactory;%0A
 import n
@@ -416,16 +416,73 @@
 tyUtils;
+%0Aimport org.bukkit.event.player.AsyncPlayerPreLoginEvent;
 %0A%0Aimport
@@ -1532,32 +1532,67 @@
        %7D else %7B%0A
+            PlayerProfile profile;%0A
             Prox
@@ -1625,24 +1625,25 @@
 roxyData();%0A
+%0A
             
@@ -1791,34 +1791,26 @@
         
-session.setPlayer(
+profile = 
 new Play
@@ -1830,17 +1830,16 @@
 e, uuid)
-)
 ;%0A      
@@ -1865,37 +1865,112 @@
             
-PlayerProfile
+profile = proxy.getProfile();%0A                if (profile == null) %7B%0A                   
  profile = p
@@ -1977,32 +1977,36 @@
 roxy.getProfile(
+name
 );%0A             
@@ -2012,92 +2012,643 @@
     
-session.setPlayer(profile == null ? proxy.getProfile(name) : profile);%0A            %7D
+%7D%0A            %7D%0A%0A            final AsyncPlayerPreLoginEvent event = EventFactory.onPlayerPreLogin(profile.getName(), session.getAddress(), profile.getUniqueId());%0A            if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) %7B%0A                session.disconnect(event.getKickMessage(), true);%0A                return;%0A            %7D%0A%0A            final PlayerProfile finalProfile = profile;%0A            session.getServer().getScheduler().runTask(null, new Runnable() %7B%0A                @Override%0A                public void run() %7B%0A                    session.setPlayer(finalProfile);%0A                %7D%0A            %7D);
 %0A   

Implement (Async)PlayerPreLoginEvent for offline mode (proxy mode too) and fixed world loading