1+ package com .xaoxiao .convenientaccess .listener ;
2+
3+ import java .util .concurrent .CompletableFuture ;
4+ import java .util .concurrent .TimeUnit ;
5+
6+ import org .bukkit .ChatColor ;
7+ import org .bukkit .entity .Player ;
8+ import org .bukkit .event .EventHandler ;
9+ import org .bukkit .event .EventPriority ;
10+ import org .bukkit .event .Listener ;
11+ import org .bukkit .event .player .AsyncPlayerPreLoginEvent ;
12+ import org .bukkit .event .player .PlayerJoinEvent ;
13+ import org .slf4j .Logger ;
14+ import org .slf4j .LoggerFactory ;
15+
16+ import com .xaoxiao .convenientaccess .ConvenientAccessPlugin ;
17+ import com .xaoxiao .convenientaccess .whitelist .WhitelistManager ;
18+
19+ /**
20+ * 白名单监听器
21+ * 监听玩家连接事件,验证白名单并阻止未授权玩家进入
22+ */
23+ public class WhitelistListener implements Listener {
24+ private static final Logger logger = LoggerFactory .getLogger (WhitelistListener .class );
25+
26+ private final ConvenientAccessPlugin plugin ;
27+ private final WhitelistManager whitelistManager ;
28+
29+
30+
31+ public WhitelistListener (ConvenientAccessPlugin plugin ) {
32+ this .plugin = plugin ;
33+ this .whitelistManager = plugin .getWhitelistSystem ().getWhitelistManager ();
34+ }
35+
36+ /**
37+ * 处理玩家预登录事件(异步)
38+ * 在玩家实际进入服务器前检查白名单
39+ */
40+ @ EventHandler (priority = EventPriority .HIGHEST )
41+ public void onAsyncPlayerPreLogin (AsyncPlayerPreLoginEvent event ) {
42+ String playerName = event .getName ();
43+ String playerUuid = event .getUniqueId ().toString ();
44+
45+ logger .debug ("检查玩家白名单状态: {} ({})" , playerName , playerUuid );
46+
47+ try {
48+ // 检查白名单系统是否已初始化
49+ if (!plugin .getWhitelistSystem ().isInitialized ()) {
50+ logger .warn ("白名单系统未初始化,允许玩家 {} 进入" , playerName );
51+ return ;
52+ }
53+
54+ // 检查配置是否启用白名单
55+ if (!plugin .getConfigManager ().isWhitelistEnabled ()) {
56+ logger .debug ("白名单功能已禁用,允许玩家 {} 进入" , playerName );
57+ return ;
58+ }
59+
60+ // 异步检查玩家是否在白名单中
61+ CompletableFuture <Boolean > whitelistCheck = whitelistManager .isPlayerWhitelisted (playerUuid );
62+
63+ // 等待结果(设置合理的超时时间)
64+ Boolean isWhitelisted = whitelistCheck .get (5 , TimeUnit .SECONDS );
65+
66+ if (!isWhitelisted ) {
67+ // 玩家不在白名单中,拒绝连接
68+ String kickMessage = getCustomKickMessage (playerName );
69+ event .disallow (AsyncPlayerPreLoginEvent .Result .KICK_WHITELIST , kickMessage );
70+
71+ logger .info ("拒绝玩家连接(未在白名单中): {} ({})" , playerName , playerUuid );
72+
73+ // 记录操作日志
74+ logUnauthorizedAccess (playerName , playerUuid , event .getAddress ().getHostAddress ());
75+ } else {
76+ logger .info ("允许玩家连接(已在白名单中): {} ({})" , playerName , playerUuid );
77+ }
78+
79+ } catch (java .util .concurrent .TimeoutException | java .util .concurrent .ExecutionException | InterruptedException e ) {
80+ logger .error ("检查玩家白名单状态时发生错误: {} ({})" , playerName , playerUuid , e );
81+
82+ // 发生错误时的处理策略
83+ if (plugin .getConfigManager ().isWhitelistStrictMode ()) {
84+ // 严格模式:发生错误时拒绝连接
85+ event .disallow (
86+ AsyncPlayerPreLoginEvent .Result .KICK_OTHER ,
87+ "§c白名单验证失败,请稍后重试"
88+ );
89+ logger .warn ("严格模式下拒绝玩家连接(白名单验证失败): {}" , playerName );
90+ } else {
91+ // 宽松模式:发生错误时允许连接
92+ logger .warn ("宽松模式下允许玩家连接(白名单验证失败): {}" , playerName );
93+ }
94+ }
95+ }
96+
97+ /**
98+ * 处理玩家加入事件
99+ * 发送欢迎消息给白名单玩家
100+ */
101+ @ EventHandler (priority = EventPriority .MONITOR )
102+ public void onPlayerJoin (PlayerJoinEvent event ) {
103+ Player player = event .getPlayer ();
104+ String playerUuid = player .getUniqueId ().toString ();
105+
106+ // 异步检查玩家信息并发送消息
107+ whitelistManager .getPlayerByUuid (playerUuid ).thenAccept (entryOpt -> {
108+ if (entryOpt .isPresent ()) {
109+ // 向管理员发送玩家加入通知
110+ if (plugin .getConfigManager ().isJoinNotificationEnabled ()) {
111+ sendJoinNotificationToAdmins (player , entryOpt .get ());
112+ }
113+
114+ // 向玩家发送自定义欢迎消息
115+ if (plugin .getConfigManager ().isWelcomeMessageEnabled ()) {
116+ sendWelcomeMessage (player );
117+ }
118+ }
119+ }).exceptionally (throwable -> {
120+ logger .error ("处理玩家加入事件时发生错误: {}" , player .getName (), throwable );
121+ return null ;
122+ });
123+ }
124+
125+ /**
126+ * 获取自定义踢出消息
127+ */
128+ private String getCustomKickMessage (String playerName ) {
129+ String template = plugin .getConfigManager ().getWhitelistKickMessage ();
130+
131+ // 替换占位符
132+ return template
133+ .replace ("{player}" , playerName )
134+ .replace ("{server}" , plugin .getServer ().getName ())
135+ .replace ("{contact}" , plugin .getConfigManager ().getContactInfo ())
136+ .replace ("&" , "§" ); // 支持颜色代码
137+ }
138+
139+ /**
140+ * 记录未授权访问
141+ */
142+ private void logUnauthorizedAccess (String playerName , String playerUuid , String ipAddress ) {
143+ logger .warn ("未授权访问尝试 - 玩家: {} ({}), IP: {}" , playerName , playerUuid , ipAddress );
144+
145+ // TODO: 可以扩展为写入数据库操作日志
146+ // plugin.getDatabaseManager().executeAsync(connection -> {
147+ // // 插入操作日志
148+ // return null;
149+ // });
150+ }
151+
152+ /**
153+ * 向管理员发送玩家加入通知
154+ */
155+ private void sendJoinNotificationToAdmins (Player player , com .xaoxiao .convenientaccess .whitelist .WhitelistEntry entry ) {
156+ String notification = ChatColor .GREEN + "" + ChatColor .BOLD + "[白名单] " +
157+ ChatColor .YELLOW + player .getName () +
158+ ChatColor .GRAY + " 已加入服务器 " +
159+ ChatColor .DARK_GRAY + "(添加者: " + entry .getAddedByName () + ")" ;
160+
161+ // 发送给有权限的管理员
162+ String permission = plugin .getConfigManager ().getJoinNotificationPermission ();
163+ plugin .getServer ().getOnlinePlayers ().stream ()
164+ .filter (p -> p .hasPermission (permission ))
165+ .forEach (admin -> admin .sendMessage (notification ));
166+ }
167+
168+ /**
169+ * 发送欢迎消息给玩家
170+ */
171+ private void sendWelcomeMessage (Player player ) {
172+ String welcomeTemplate = plugin .getConfigManager ().getWelcomeMessage ();
173+ String welcomeMessage = welcomeTemplate
174+ .replace ("{player}" , player .getName ())
175+ .replace ("{server}" , plugin .getServer ().getName ())
176+ .replace ("&" , "§" );
177+
178+ // 延迟1秒发送,确保玩家完全加入
179+ plugin .getServer ().getScheduler ().runTaskLater (plugin , () -> {
180+ player .sendMessage (welcomeMessage );
181+ }, 20L );
182+ }
183+ }
0 commit comments