This uses the AsyncPlayerPreLoginEvent through Skript-Reflect, stopping most loading before it starts happening - Unlike the on connect or on join events through Skript.
Using AsyncPlayerPreLogin Event and ServerListPing Event, I am able to check if a player's ip has ever loaded the server on their title menu screen. If they haven't, then they can not join. Once they have, they can join with no problems. This stops the majority of bots which do not load the server on a server list, and allows players easy access to the server. The only downside is, this fully disables Direct Connect if they have not loaded it before. But then, who really uses Direct Connect?
Using the same technique through a command I have also made a better whitelist (unlike the vanilla one which for some reason never works exactly right)