3838import net .kyori .adventure .text .minimessage .MiniMessage ;
3939
4040import org .bstats .bukkit .Metrics ;
41+ import org .bukkit .OfflinePlayer ;
4142import org .bukkit .command .Command ;
4243import org .bukkit .command .CommandSender ;
4344import org .bukkit .entity .Player ;
4445import org .bukkit .event .EventHandler ;
4546import org .bukkit .event .Listener ;
4647import org .bukkit .event .player .AsyncPlayerPreLoginEvent ;
48+ import org .bukkit .event .player .PlayerJoinEvent ;
4749import org .bukkit .plugin .java .JavaPlugin ;
4850
4951import java .io .File ;
52+ import java .net .InetAddress ;
5053import java .net .InetSocketAddress ;
5154import java .util .Arrays ;
5255import java .util .List ;
@@ -162,6 +165,7 @@ public void onEnable() {
162165
163166 getServer ().getPluginManager ().registerEvents (this , this );
164167 getCommand ("discordsrvoauth" ).setExecutor (this );
168+ getCommand ("link" ).setExecutor (this );
165169 }
166170
167171 @ Override
@@ -220,6 +224,44 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String
220224 }
221225 }
222226
227+ if (cmd .getName ().equalsIgnoreCase ("link" )) {
228+ if (!(sender instanceof Player )) {
229+ sender .sendMessage ("§cThis command can only be used by players." );
230+ return true ;
231+ }
232+
233+ Player player = (Player ) sender ;
234+
235+ AccountLinkManager accountLinkManager = DiscordSRV .getPlugin ().getAccountLinkManager ();
236+ if (accountLinkManager == null ) {
237+ player .sendMessage (
238+ DiscordSRV .config ()
239+ .getString (
240+ "Require linked account to play.Messages.DiscordSRV still"
241+ + " starting" )
242+ .replaceAll ("&" , "§" ));
243+ return true ;
244+ }
245+
246+ if (accountLinkManager .getDiscordIdBypassCache (player .getUniqueId ()) != null ) {
247+ player .sendMessage (
248+ DiscordSRV .config ()
249+ .getString ("MinecraftAccountAlreadyLinked" )
250+ .replaceAll ("&" , "§" ));
251+ return true ;
252+ }
253+
254+ String message = makeLinkMessage (player .getUniqueId (), accountLinkManager );
255+ try {
256+ Class .forName ("net.kyori.adventure.text.minimessage.MiniMessage" );
257+ player .sendMessage (MiniMessage .miniMessage ().deserialize (message ));
258+ } catch (Exception e ) {
259+ player .sendMessage (message );
260+ }
261+
262+ return true ;
263+ }
264+
223265 return false ;
224266 }
225267
@@ -237,43 +279,113 @@ public List<String> onTabComplete(
237279
238280 @ SuppressWarnings ("deprecation" )
239281 @ EventHandler (ignoreCancelled = true )
240- public void onPlayerJoin (AsyncPlayerPreLoginEvent event ) {
282+ public void onPlayerPreLogin (AsyncPlayerPreLoginEvent event ) {
283+ if (!DiscordSRV .config ().getBoolean ("Require linked account to play.Enabled" )) return ;
284+
241285 AccountLinkManager accountLinkManager = DiscordSRV .getPlugin ().getAccountLinkManager ();
242286 if (accountLinkManager == null ) return ;
243287
244- UUID playerUuid = event .getUniqueId ();
245- String discordId = accountLinkManager .getDiscordIdBypassCache (playerUuid );
288+ if (bypassLinkCheck (event .getName (), event .getUniqueId (), event .getAddress ())) return ;
246289
247- if (discordId == null ) {
248- String code = accountLinkManager .generateCode (playerUuid );
249- String route = "/" + config .getLinkRoute () + "?code=" + code ;
290+ if (!DiscordSRV .isReady ) {
291+ event .disallow (
292+ AsyncPlayerPreLoginEvent .Result .KICK_WHITELIST ,
293+ DiscordSRV .config ()
294+ .getString (
295+ "Require linked account to play.Messages.DiscordSRV still"
296+ + " starting" )
297+ .replaceAll ("&" , "§" ));
298+ return ;
299+ }
250300
251- String botName = "Discord Bot" ;
301+ if (accountLinkManager .getDiscordIdBypassCache (event .getUniqueId ()) == null ) {
302+ String message = makeLinkMessage (event .getUniqueId (), accountLinkManager );
252303 try {
253- botName = DiscordSRV .getPlugin ().getMainGuild ().getSelfMember ().getEffectiveName ();
254- } catch (Exception ignored ) {
304+ Class .forName ("net.kyori.adventure.text.minimessage.MiniMessage" );
305+ event .disallow (
306+ AsyncPlayerPreLoginEvent .Result .KICK_WHITELIST ,
307+ MiniMessage .miniMessage ().deserialize (message ));
308+ } catch (Exception e ) {
309+ event .disallow (AsyncPlayerPreLoginEvent .Result .KICK_WHITELIST , message );
255310 }
311+ }
312+ }
313+
314+ @ EventHandler
315+ public void onPlayerJoin (PlayerJoinEvent event ) {
316+ if (DiscordSRV .config ().getBoolean ("Require linked account to play.Enabled" )) return ;
256317
257- String kickMessage =
258- config .getKickMessage ()
259- .replaceAll ("&" , "§" )
260- .replace ("{JOIN}" , Utils .getBaseURL (config , true ) + route )
261- .replace ("{KICK}" , Utils .getBaseURL (config , false ) + route )
262- .replace ("{CODE}" , code )
263- .replace ("{BOT}" , botName );
318+ AccountLinkManager accountLinkManager = DiscordSRV .getPlugin ().getAccountLinkManager ();
319+ if (accountLinkManager == null ) return ;
264320
321+ Player player = event .getPlayer ();
322+
323+ if (bypassLinkCheck (
324+ player .getName (), player .getUniqueId (), player .getAddress ().getAddress ())) return ;
325+
326+ if (accountLinkManager .getDiscordIdBypassCache (player .getUniqueId ()) == null ) {
327+ String message = makeLinkMessage (player .getUniqueId (), accountLinkManager );
265328 try {
266329 Class .forName ("net.kyori.adventure.text.minimessage.MiniMessage" );
267-
268- event .disallow (
269- AsyncPlayerPreLoginEvent .Result .KICK_WHITELIST ,
270- MiniMessage .miniMessage ().deserialize (kickMessage ));
330+ player .sendMessage (MiniMessage .miniMessage ().deserialize (message ));
271331 } catch (Exception e ) {
272- event . disallow ( AsyncPlayerPreLoginEvent . Result . KICK_WHITELIST , kickMessage );
332+ player . sendMessage ( message );
273333 }
274334 }
275335 }
276336
337+ private boolean bypassLinkCheck (String playerName , UUID playerUuid , InetAddress address ) {
338+ if (DiscordSRV .config ()
339+ .getStringList ("Require linked account to play.Bypass names" )
340+ .contains (playerName )) return true ;
341+
342+ if (DiscordSRV .config ()
343+ .getBoolean ("Require linked account to play.Whitelisted players bypass check" )) {
344+ if (getServer ().getWhitelistedPlayers ().stream ()
345+ .map (OfflinePlayer ::getUniqueId )
346+ .anyMatch (playerUuid ::equals )) {
347+ return true ;
348+ }
349+ }
350+
351+ boolean onlyCheckBanned =
352+ DiscordSRV .config ()
353+ .getBoolean ("Require linked account to play.Only check banned players" );
354+
355+ if (!DiscordSRV .config ().getBoolean ("Require linked account to play.Check banned players" )
356+ || onlyCheckBanned ) {
357+ boolean banned =
358+ getServer ().getBannedPlayers ().stream ()
359+ .anyMatch (p -> p .getUniqueId ().equals (playerUuid ));
360+
361+ if (!banned )
362+ banned =
363+ getServer ().getIPBans ().stream ().anyMatch (address .getHostAddress ()::equals );
364+ if (!onlyCheckBanned && banned ) return true ;
365+ if (onlyCheckBanned && !banned ) return true ;
366+ }
367+
368+ return false ;
369+ }
370+
371+ private String makeLinkMessage (UUID playerUuid , AccountLinkManager accountLinkManager ) {
372+ String code = accountLinkManager .generateCode (playerUuid );
373+ String route = "/" + config .getLinkRoute () + "?code=" + code ;
374+
375+ String botName = "Discord Bot" ;
376+ try {
377+ botName = DiscordSRV .getPlugin ().getMainGuild ().getSelfMember ().getEffectiveName ();
378+ } catch (Exception ignored ) {
379+ }
380+
381+ return config .getKickMessage ()
382+ .replaceAll ("&" , "§" )
383+ .replace ("{JOIN}" , Utils .getBaseURL (config , true ) + route )
384+ .replace ("{KICK}" , Utils .getBaseURL (config , false ) + route )
385+ .replace ("{CODE}" , code )
386+ .replace ("{BOT}" , botName );
387+ }
388+
277389 private void startServer () {
278390 stopServer ();
279391
0 commit comments