@@ -31,7 +31,6 @@ public class PlayerConnectionManager {
3131 private final Logger logger ;
3232 private final ProxyServer server ;
3333 private final ConfigManager configManager ;
34- private final Object plugin ;
3534 private final DatabaseManager databaseManager ;
3635 private final GeoIPManager geoIPManager ;
3736
@@ -95,11 +94,10 @@ public class PlayerConnectionManager {
9594 });
9695
9796 public PlayerConnectionManager (Logger logger , ProxyServer server , ConfigManager configManager ,
98- Path dataPath , Object plugin ) {
97+ Path dataPath ) {
9998 this .logger = logger ;
10099 this .server = server ;
101100 this .configManager = configManager ;
102- this .plugin = plugin ;
103101
104102 // 初始化数据库管理器
105103 this .databaseManager = new DatabaseManager (logger , dataPath , configManager );
@@ -184,105 +182,125 @@ public void initializePlayer(Player player) {
184182 // 默认启用延迟监控
185183 pingMonitorEnabled .putIfAbsent (uuid , true );
186184
187- // 获取IP信息(异步,仅在第一次连接时检测)
188- if (!ipInfoCache .containsKey (uuid )) {
189- detectIPInfo (player );
190- }
191-
192185 // 如果玩家没有历史线路记录,尝试从数据库加载
193- if (!lastRoutes .containsKey (uuid )) {
186+ boolean hasExistingRoute = lastRoutes .containsKey (uuid );
187+ if (!hasExistingRoute ) {
194188 String savedRoute = loadPlayerRoute (uuid );
195189 if (savedRoute != null ) {
196190 lastRoutes .put (uuid , savedRoute );
191+ hasExistingRoute = true ;
197192 logDebug ("玩家 {} 从数据库加载线路记录: {}" , player .getUsername (), savedRoute );
198193
199194 CompletableFuture .supplyAsync (() -> databaseManager .saveRoute (uuid , savedRoute , player .getUsername ()), databaseExecutor )
200195 .exceptionally (e -> {
201196 logger .error ("更新玩家 {} 的用户名记录时出错" , player .getUsername (), e );
202197 return false ;
203198 });
204- } else {
205- // 数据库也没有记录,检测玩家地理位置后设置默认线路
206- setDefaultRouteForNewPlayer (player );
207199 }
208200 }
201+
202+ // 获取IP信息(异步,仅在第一次连接时检测)
203+ if (!ipInfoCache .containsKey (uuid )) {
204+ detectIPInfo (player , hasExistingRoute );
205+ } else {
206+ applyRulesForPlayer (player , hasExistingRoute );
207+ }
209208 }
210209
211210 /**
212- * 为新玩家设置默认线路(根据配置文件设置)
211+ * 根据规则为玩家分配或覆写线路
212+ * @param player 当前玩家
213+ * @param hasHistory 是否已经存在历史线路(true 表示允许覆盖已有线路)
213214 */
214- private void setDefaultRouteForNewPlayer (Player player ) {
215+ private void applyRulesForPlayer (Player player , boolean hasHistory ) {
216+ if (!configManager .isRulesEnabled ()) {
217+ return ;
218+ }
219+
215220 UUID uuid = player .getUniqueId ();
216-
217- // 异步检测完成后设置默认线路
218- server .getScheduler ().buildTask (plugin , () -> {
219- IPInfo info = ipInfoCache .get (uuid );
220-
221- if (info == null ) {
222- logDebug ("玩家 {} IP 信息未就绪,跳过规则匹配" , player .getUsername ());
223- return ;
224- }
225-
226- // 检查是否有历史记录
227- boolean hasHistory = databaseManager .getRoute (uuid ) != null ;
228-
229- // 获取虚拟主机信息
230- String hostname = player .getVirtualHost ()
221+ IPInfo info = ipInfoCache .get (uuid );
222+
223+ if (info == null ) {
224+ logDebug ("玩家 {} IP 信息未就绪,暂不应用路由规则" , player .getUsername ());
225+ return ;
226+ }
227+
228+ String hostname = player .getVirtualHost ()
231229 .map (address -> address .getHostString ())
232230 .orElse ("unknown" );
233-
234- // 构建玩家上下文
235- TransferRule .PlayerContext context = new TransferRule .PlayerContext (
236- info .country , // country: 国家
237- info .province , // province: 省份
238- info .isp , // isp: 运营商
239- hasHistory , // has_history: 是否有历史记录
240- uuid , // uuid: 玩家 UUID
241- hostname // hostname: 虚拟主机名
242- );
243-
244- // 尝试匹配规则
245- List <TransferRule > rules = configManager .getTransferRules ();
246- for (TransferRule rule : rules ) {
247- if (rule .matches (context )) {
248- String targetRoute = rule .executeAction ();
249-
250- if (targetRoute != null ) {
251- // 检查目标线路是否存在
252- if (configManager .getTransferServers ().containsKey (targetRoute )) {
253- // 检查是否最近连接失败过
254- if (isServerRecentlyFailed (uuid , targetRoute )) {
255- logger .warn ("玩家 {} 匹配规则 [{}] 但目标线路 {} 最近连接失败,跳过此规则" ,
256- player .getUsername (), rule .getName (), targetRoute );
257- continue ; // 尝试下一个规则
258- }
259-
260- lastRoutes .put (uuid , targetRoute );
261- logDebug ("玩家 {} 匹配规则 [{}],分配 {} 线路" ,
262- player .getUsername (), rule .getName (), targetRoute .toUpperCase ());
263- return ; // 匹配到规则后立即返回
264- } else {
265- logger .warn ("规则 [{}] 指定的线路 {} 不存在,玩家 {} 跳过此规则" ,
266- rule .getName (), targetRoute , player .getUsername ());
267- }
268- } else {
269- logDebug ("玩家 {} 匹配规则 [{}],跳过自动分配" ,
270- player .getUsername (), rule .getName ());
271- return ; // skip 动作也会停止后续规则匹配
272- }
273- }
231+
232+ TransferRule .PlayerContext context = new TransferRule .PlayerContext (
233+ info .country ,
234+ info .province ,
235+ info .isp ,
236+ hasHistory ,
237+ uuid ,
238+ hostname
239+ );
240+
241+ List <TransferRule > rules = configManager .getTransferRules ();
242+ if (rules .isEmpty ()) {
243+ return ;
244+ }
245+
246+ for (TransferRule rule : rules ) {
247+ if (!rule .matches (context )) {
248+ continue ;
274249 }
275-
276- // 如果没有规则匹配或所有匹配的服务器都失败过,使用安全服务器
250+
251+ String targetRoute = rule .executeAction ();
252+
253+ if (targetRoute == null ) {
254+ logDebug ("玩家 {} 匹配规则 [{}],执行 skip 动作" , player .getUsername (), rule .getName ());
255+ return ;
256+ }
257+
258+ if (!configManager .getTransferServers ().containsKey (targetRoute )) {
259+ logger .warn ("规则 [{}] 指定的线路 {} 不存在,玩家 {} 跳过此规则" , rule .getName (), targetRoute , player .getUsername ());
260+ continue ;
261+ }
262+
263+ if (isServerRecentlyFailed (uuid , targetRoute )) {
264+ logger .warn ("玩家 {} 匹配规则 [{}] 但目标线路 {} 最近连接失败,跳过此规则" , player .getUsername (), rule .getName (), targetRoute );
265+ continue ;
266+ }
267+
268+ String previousRoute = lastRoutes .get (uuid );
269+ if (previousRoute != null && previousRoute .equalsIgnoreCase (targetRoute )) {
270+ logDebug ("玩家 {} 匹配规则 [{}],已在线路 {},无需调整" , player .getUsername (), rule .getName (), targetRoute .toUpperCase ());
271+ return ;
272+ }
273+
274+ lastRoutes .put (uuid , targetRoute );
275+
276+ if (hasHistory && previousRoute != null ) {
277+ logger .info ("玩家 {} 匹配规则 [{}],线路从 {} 切换为 {}" , player .getUsername (), rule .getName (), previousRoute .toUpperCase (), targetRoute .toUpperCase ());
278+ } else {
279+ logDebug ("玩家 {} 匹配规则 [{}],分配 {} 线路" , player .getUsername (), rule .getName (), targetRoute .toUpperCase ());
280+ }
281+
282+ CompletableFuture .supplyAsync (() -> databaseManager .saveRoute (uuid , targetRoute , player .getUsername ()), databaseExecutor )
283+ .thenAccept (saved -> {
284+ if (!saved ) {
285+ logger .warn ("保存玩家 {} 的线路 {} 时失败" , player .getUsername (), targetRoute );
286+ }
287+ })
288+ .exceptionally (e -> {
289+ logger .error ("保存玩家 {} 的线路记录时发生异常" , player .getUsername (), e );
290+ return null ;
291+ });
292+ return ;
293+ }
294+
295+ if (!hasHistory ) {
277296 if (configManager .isTransferTimeoutProtectionEnabled ()) {
278297 String safeServer = getSafeServer (uuid );
279298 logDebug ("玩家 {} 未匹配任何有效规则,使用安全服务器: {}" , player .getUsername (), safeServer );
280299 lastRoutes .put (uuid , safeServer );
281300 } else {
282- // 如果没有规则匹配,不自动分配线路(由玩家手动选择)
283301 logDebug ("玩家 {} 未匹配任何规则,不自动分配线路" , player .getUsername ());
284302 }
285- }). delay ( 1 , TimeUnit . SECONDS ). schedule ();
303+ }
286304 }
287305
288306 /**
@@ -462,7 +480,7 @@ public CompletableFuture<Boolean> updateOfflineRoute(UUID targetUuid, String rou
462480 String displayName = targetDisplayName != null ? targetDisplayName : targetUuid .toString ();
463481 String operatorName = operatorDisplayName != null ? operatorDisplayName : "未知操作源" ;
464482
465- logger . info ("管理员 {} 将玩家 {} ({}) 的线路记录更新为 {}" , operatorName , displayName , targetUuid , routeName );
483+ logDebug ("管理员 {} 将玩家 {} ({}) 的线路记录更新为 {}" , operatorName , displayName , targetUuid , routeName );
466484
467485 return CompletableFuture .supplyAsync (() -> databaseManager .saveRoute (targetUuid , routeName , targetDisplayName ), databaseExecutor )
468486 .thenApply (saved -> {
@@ -936,7 +954,7 @@ private void sendRouteRecommendations(Player player, IPInfo ipInfo, String curre
936954 /**
937955 * 检测IP信息
938956 */
939- private void detectIPInfo (Player player ) {
957+ private void detectIPInfo (Player player , boolean hasExistingRoute ) {
940958 UUID uuid = player .getUniqueId ();
941959
942960 try {
@@ -979,6 +997,8 @@ private void detectIPInfo(Player player) {
979997
980998 logDebug ("IP地理位置 {} → {} - {} [{}]" ,
981999 player .getUsername (), location .toString (), info .isp , ip );
1000+
1001+ applyRulesForPlayer (player , hasExistingRoute );
9821002
9831003 } catch (Exception e ) {
9841004 logger .error ("IP检测失败 {}: {}" , player .getUsername (), e .getMessage ());
0 commit comments