From e616667c781c263975c41e3ba847257bc8ec3246 Mon Sep 17 00:00:00 2001 From: loki5512344 Date: Fri, 23 Jan 2026 21:52:17 +0100 Subject: [PATCH] Fix missing features and improve code quality Features fixed: - Added chat filter functionality (block/warn/censor modes) - Fixed spy command to monitor all chat messages - Added proper spy notifications for global/local chat Code quality improvements: - Created PlayerUtil to eliminate code duplication in player lookup - Refactored ChatListener into smaller, focused methods - Added Constants class to replace magic numbers - Improved SOLID principles compliance - Fixed all compilation warnings All features from README are now implemented and working. --- .../lochat/commands/ClearChatCommand.class | Bin 2204 -> 2241 bytes .../loki/lochat/commands/MuteCommand.class | Bin 9211 -> 8939 bytes .../lochat/commands/MuteHistoryCommand.class | Bin 7000 -> 6606 bytes .../loki/lochat/commands/UnmuteCommand.class | Bin 6241 -> 5961 bytes .../loki/lochat/config/ConfigManager.class | Bin 8519 -> 8556 bytes .../loki/lochat/listeners/ChatListener.class | Bin 8856 -> 11150 bytes .../com/loki/lochat/managers/SpyManager.class | Bin 2697 -> 3760 bytes .../com/loki/lochat/utils/Constants.class | Bin 0 -> 803 bytes .../com/loki/lochat/utils/PlayerUtil.class | Bin 0 -> 1655 bytes bin/main/messages.yml | 3 +- .../lochat/commands/ClearChatCommand.java | 4 +- .../com/loki/lochat/commands/MuteCommand.java | 24 +-- .../lochat/commands/MuteHistoryCommand.java | 18 +-- .../loki/lochat/commands/UnmuteCommand.java | 24 +-- .../com/loki/lochat/config/ConfigManager.java | 2 +- .../loki/lochat/listeners/ChatListener.java | 151 ++++++++++++------ .../com/loki/lochat/managers/SpyManager.java | 19 +++ .../java/com/loki/lochat/utils/Constants.java | 31 ++++ .../com/loki/lochat/utils/PlayerUtil.java | 70 ++++++++ src/main/resources/messages.yml | 3 +- 20 files changed, 250 insertions(+), 99 deletions(-) create mode 100644 bin/main/com/loki/lochat/utils/Constants.class create mode 100644 bin/main/com/loki/lochat/utils/PlayerUtil.class create mode 100644 src/main/java/com/loki/lochat/utils/Constants.java create mode 100644 src/main/java/com/loki/lochat/utils/PlayerUtil.java diff --git a/bin/main/com/loki/lochat/commands/ClearChatCommand.class b/bin/main/com/loki/lochat/commands/ClearChatCommand.class index 96253d11552faab1aa97f81a511ad957c5a9fb86..87ca74e9722b7b3ecd2d439240354adf68ca2a22 100644 GIT binary patch delta 450 zcmZXQZA+736vuzp?uWDHgf_%bghpuv!bYH3`KA7&AHoqGDi?0eu7?I z?;<}$1kr+mUiiju(dP(SS9@7+&iQkG=bS(MKO}x6Vi&)^eg~#G{206D_`;ClsyTD7 zq-)`ELx+vy7iT-_Dm=F*!HuuaXlUnfLB3=P_&M++Fb3E;coaAJ_;0`vKR^&gk@P&s>@)3IcCQr>fSv`HmbCgZz6))H#(pE3o z#%Ze^G%h_hyIqQS^wG^8CB*K-I&ORQp+I6%@x9__C PKjgrK(VJ4W1`&ckw0~JO delta 388 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 KX)1jho(};9R>;x- diff --git a/bin/main/com/loki/lochat/commands/UnmuteCommand.class b/bin/main/com/loki/lochat/commands/UnmuteCommand.class index f4f970fd0c75dcf4f635bf7c16bee4124324569b..c69e194620064a3304dbc394a3193fff838cf77f 100644 GIT binary patch delta 2048 zcmZvddvsLQ6~=#OW-{l_olAyHAjwS^5I_tum;_vEIxG+ht&4{-3Xwn&Gms%fh73$@ zP+H5>N41nz!PBb2XCE3{qhQgIK@GmDVpVJ_Vq02EYaeP`^}ntzmvPS|BrajioV)kg z=ezrLzH{!0hQoFCE1w=50Os@YqxQjosxnn}+0^D_d|M*j;&mn+7O_}SyuP!mec0Nv zXrbZ^v&AYMSF`lW_||xRj{xgi#6H_%sTnA$oM+QSv*uz&Nh;k@zqV)N#!j#PD+S?j z370BD9SLv9qhiMNFE}!v1gdJ5JG5|_V$2A#DZVKou}?wI*W>Ik6KQo=$tn{GPPT2% zV70^LtT7$IxxqHpYT~BEUup(|W&U-vn`6OqgXrny=iR+?rj;{OKUG;6IzRvX`P*iOdmx30IE zxYpr1t~YZ-4O70uO`01O<3?MyAeBre)_I+&E{E^3!|V#3S+$cNXuhwAj=~msiFDjc zr5$eO7V}o9s(QDgESXxjA@0>}>hThF-HF86-JQuqmlq~UmCX;iP4go&!JdBh?KCKg zHpkQ5iTvWMFgw}fa3^;u^oDqMQ{rk*;h$c!%HkfAv@6wp<|eyYlK+XrPx+a7$8J;) zn2PY*X1Y^lJ_G-y#o!y?zVInqj zc+KH;Rw=?>YH8}KM0!DdD5=)`;%^*&%M^v(?Zwkx_liz$Lzp*tOLJ5RIO;a<(cu_x zOV;uBcE$K%J|xWt#fO6L@(<15&Av#Dzk`38h|t?b=zc=;iTRH*}B$ zdRex{!Y3Vs-H>Z5mCbNXEPQ}(=eR-qkLjb@9h2jGif2g19M_5N%5kfYULvmJ3ee=Z zLjnn=SFvaCXdkmrhPXR=?`cEiBNSdez>in-5w4BiU&uDlFE>NRPpOE5)XB4oFq4_U z6ecl^Gv!xDH4W5q4l_7UW=p7-Q`w+xJBZ}Bl<}0wEU)!Ra8=NL&M)v4w1?=&U(g=r z5n;tSD$^?Y^;5)os)c<#D%@Ct%P+;IrIJtB&tszPm8>6^Dl8dCc|ul0QqOA~5Y3jv zFBSsy6PDB~q?cJ7Npu2F=50JB`MgK*q_Kn2>aa#>CTgD6%+Vamh)^i89YXw+odU?O z=f_Eeby~zp557U!ME!*rg%DE8B+WCQGGCJvi~I*Um*vH$0Sj&fBsi&mCrlm0Ic@CE zqoH2&oLN#x6Lw^-%Nu+w+Wp8;Ur*B}4@ delta 2357 zcmaKud3;pW7017KGBfYZn-`J{A>;*(NudyuLK0BqGm5gQjieH>Nf5MgOeV>YGy^je z2wEM{y0o@MdqoMgfJ+;zXtio!D1u$wsJ7IlwOd--O84E?+G@x1CIRHr;2(3}dFTG_ zS%2rgd2aS=b=JZE?cEP7;=hkrd%e?(;)$->%lmtJVyW82xra>y=PLqT(Nt4!WMed; zn5_%F#d?#k{G>*kk8pvaP%~O{_4uP*Hj!jLk)SR8i0! zN#?9}ERJ@@6H!H8)y!4y`4*d27h%Sd%llmCCKoFvM-z#7A~}0)Z)B;&JF73An$;Qa z@9S`nthTv?OBF$hxVbO3u0Pt)p$JvYY+MsrAF1t6#d>R-n;Vwq;%l?HjEFw$t2BeO zv)Z6T*Beuc-Iul?<+NE$quVCN8eQZ+%il|%!N+w`-bCH)FUgCuR&Vm3=14OE&9xWllOVFUKyBPv4uMfZkNoCrPYv%CL*c0 z1hbVvy**H&zMu~TrUcumu-MK{gB|+yK-G-9s8jgXMiR-Wo9LV%Te#QeOKznN>BR-n zft1OR4qIjFE4tZgl3*UN*~NqUL2JJHsy=MJsz-wJ_5NT*O@91%T9lob5xUr3=zUI6 zrf*eceuLcx&p$d~Z&R^X6cdl-u_%#Vnwp9?#y3P0OCrgr ztN)43Px*ktN~R)-RI)Xe>JBo(FARRJm~hOZYs}^~eyOjSaLE5>{%Y_S-BK{qNb)zu z)+&9Vpj2-!xYqk8lQ;CV!mxT%w-r`<-%^z8CkrOao}nKoYzma(#UUUmc#F=nym#Yg z0;m^tbI~nnU)XevXJ~PJdsr5>94o_e#WpHkso9k#*Hk}7(J)g(D~GAcQ18LJ%iUe2 z2nSr@V~VHAACrdgIbw8(Nsf`>@*GA48IZ6kr#t0ojT-E70#4c*re~1HYaDYg>mbAF z9vtIoY{v-oXV~Cjl7Eos=!t>QCqh>bb4@sS#6r+99ZRWUZU_hW@aYVn6Z`o?%y9BE z+@^Sv_OR{Pp=}xN^e{+)V><%;VuriLPktuNJ(6Sgl_AbJ;^NDp`%dU0cXki=w+<1k z2|bjH*1Jotsyrsj`XZ;wdI~`*IGIY3rZJrlGF#RKW(P}nl%+hyIXuI89OA?LR_?$*a6WH{xp(Bg^U1YU z!U{E2+Ezu2s+R`MW3@V)OVlEHo+~%ZD%w<%%T!v3d9%n{(sZb;(ww`bG55&xKDyLC zy46#xQP0w&4oO(WlG84VT*@$s5_xl_hj|2*lfEXQd2-TYJT8@RcZb<6tedNLut#)0 z=BYcSw|j+p%Y=(x7oEXowS@FOo)A$>l>0?#N@i0yAZ-gsUL#}D4$1Tzd=pD@e1UHX z&XR1F^KFrWl257B8vC) z9>4{SLb4Loc!(n=JXz_sF`f^yoHg!IgLbhmc{imI&`IwDGWd?bIjG$xGWchq|Bprq@%*#c9u*yFeS~eABO!$CsD3}I>$UZiH3V6$W0(1 z$3M)E2MIa8F5~i%DkPSks z0p_q#rsN9wL=SK&SJ5RCwT?|W3a^kpy7(~)i!?@Ik;W)2(yxR+LSd0cDIB1OU-PHs71gX0y>6ZL=|fUOW{|DtM`ogBNdIL#n}KSDOv!RsRBc z5flV3p7bCRK@jRiMDV7iCj|xZv-Kl>RgFexM=u^`=J!7Hyzjg-bFa2h3*H~yy3H7? zqI^Agb-W&6&%yMD-Kn(gV=X>4j+#!T=d{}0%DioL9n*5UU=v50&Vt=A+x6wDcT7iO?sEw_+-QZS;83@NWk@KfOSsNP%V}jxR4^ zCtZouQKVs{=qrKc_+GBRKYA{J7gUvH@5|V0x}>Hktfa6ml#SRsp&aDO2fC)o7|*Sul&h#tsE8q1Y1Av_0i1}5oLZXY5dUgL3;pr?JYI1>EUNt)GVTGi8J z>IP)d(q+9uhw^D!=ZfOK2bJ>%J>klUya81dy1^+cXftmVG|_MlI$tFQ6!_SIX&wbR K&A`Aeru+fT4!x!T delta 589 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 diff --git a/bin/main/com/loki/lochat/managers/SpyManager.class b/bin/main/com/loki/lochat/managers/SpyManager.class index d18ae7c2afcf60b00096af866d9b3cdc245d6cf9..a9cb48f5891cf1ee2f040839136217225ac67fc5 100644 GIT binary patch delta 944 zcmb7BSx*yD6#i~$XK72oCTNDm5L{AZX>b8)Q347i3W3;$$YwH>0f%%;rxFX6lDL8k z>bOyN1uNo%MAJ|cjp4xu|B8=3nuupg!i!I4X72g!x#xV}neWaPeJHd3`1AQIfEK)8 zwf^J^ZJH7q@rAt+RnZt)o%+1FSTE#uH}+Td+E9T@c3j43242=VQmh!ALlygks*U z5<6~To4FLxC2F*ZR-Ov6|6vG$_XeJY=X|Pd5yBd-{gT*VD>WEFMu3gc_y{vy^DUO`FlF zprUE=n3Axf2@7^KBgN3@{8wfmm(o}A$_oTMA@?>38Fm{+yBGvj+ccDc_0!gv#z&eA z_M9bMn?gKZGgOeh75Xpk6nm$)^COJ=xWZ4Hl57qftaPtS`#xbu78e;7U|ua-fZ({2 zhQ)EsZC=A%br!cxa9gNI%HV+Gp7{&>eR+-t-V7eOxy{}d2DgxgR}!*lWB7)XZeHTo z(B&2-@jE<{n1$Eiuam^84Ej=VCM8kg9FHY)2E&fQsw~bh7;s#&P*_7Ci>L_(;RHi! zV|kS(%|i*Tttg~*Kk{)9#W;jLs3+7wPd(Y%h+eoc1P{*9E{-FZ!BM*9X1e4ir09H+ z7)p@@1|b^1k236}XrMSI!E)#Vp2Czv&+wdti;3a|5-^k83|ff$?3=9m844oUfUb9VZ;S6AGpL~@wg^_i$6;~b8s3TS^?h7bheR zd;mTPAAmFBzYalGFZeLy-^_nzXLf)5{`Q@SOnTa)8l(LvzckYPQvws6hlQ~yl5}qH zJewC`R?J(}VAQ<`KZiydW*-fEdJ#tjquxLaO<#F|vbm`O#~euCWyB<-8>`|;m@eWv z4m(2&u7v3X{MbZ^v;?%>kyJ{$fwTfwaN8Q7{CyL0eD$AU7YdyL1noRFcKk;&K|#yl|SvjJ8!Ch3O=mC7S;R8^w7tXLP9k^MY>} zwcUI%i{fFTn{BL~XZ}(@E4?C2f*m^4rzWj|TA&)OgRfoTHeLUh*ZPf0eiPii!dn&I zM*e1nd*Gc4-vaMeSf9UF;Xe3wg?0U%3a?|bn!Z8!``EyMXYkDzUupkKxzZu5UXZZd T1K7?|Ko98=h|y!%8a?>~&drif literal 0 HcmV?d00001 diff --git a/bin/main/com/loki/lochat/utils/PlayerUtil.class b/bin/main/com/loki/lochat/utils/PlayerUtil.class new file mode 100644 index 0000000000000000000000000000000000000000..63fe1931e7b1ad0f38eb6bf99f73643378bba8f4 GIT binary patch literal 1655 zcma)6%Tg0T6g`~;29n`T!b6aUC{GzsQ6Y-*RIC72AuK32Loz@^n9*cn;iss-z(QAw z3zshZCd%^k%mfl1g`2+JJ@;|WJ-6r2-=Dt#%;1%VkU)3ZIWV%$zT}eLHC?0N%52_v zoi#sNxpnR}L&7s zXS%6xS6;Wm}pHS=DP%&fKT<%X1+8()DV8~xK~>Icu9@CnHs1x4qrdZJbm36uT~1K^GTk<#5O|=Y z7IjQ;s`82lzc@W-qY_Bs&3Q0RYI+{4F_{z?2}+a(T**!iMpDNUJQdJb*{|7Ll>K~- zXG-|z*VZU+ijsq!i4+QwBUOKX^7&$ zI$ucjCm2;~W1Jlg^9KSx^N@P#JZn4|v_jnueMi+dZbFE1RiDBB$GGag18ogY)k+oK zsNgTOD(TqJ57HR^jp*<(5&~a&?pPi9z*5SIP{x;}0M literal 0 HcmV?d00001 diff --git a/bin/main/messages.yml b/bin/main/messages.yml index f148fab..6d09ec2 100644 --- a/bin/main/messages.yml +++ b/bin/main/messages.yml @@ -39,10 +39,11 @@ spy: enabled: "CADFШпион режим включен" disabled: "CADFШпион режим выключен" format: "󅒐[SPY] {sender} → {receiver}: {message}" + chat-format: "󅒐[SPY] {type} {sender}: {message}" filter: blocked: "CADFСообщение заблокировано (мат)" - warned: "CADFПредупреждение: не используйте мат!" + warning: "CADFПредупреждение: не используйте мат!" cooldown: wait: "CADFПодождите {time} сек перед следующим сообщением" diff --git a/src/main/java/com/loki/lochat/commands/ClearChatCommand.java b/src/main/java/com/loki/lochat/commands/ClearChatCommand.java index 3460c46..ff1abd1 100644 --- a/src/main/java/com/loki/lochat/commands/ClearChatCommand.java +++ b/src/main/java/com/loki/lochat/commands/ClearChatCommand.java @@ -19,9 +19,9 @@ public class ClearChatCommand implements CommandExecutor { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - // Отправляем 100 пустых строк всем игрокам + // Отправляем пустые строки всем игрокам для очистки чата for (Player player : Bukkit.getOnlinePlayers()) { - for (int i = 0; i < 100; i++) { + for (int i = 0; i < com.loki.lochat.utils.Constants.CLEAR_CHAT_LINES; i++) { player.sendMessage(""); } diff --git a/src/main/java/com/loki/lochat/commands/MuteCommand.java b/src/main/java/com/loki/lochat/commands/MuteCommand.java index 37565a4..00e31c0 100644 --- a/src/main/java/com/loki/lochat/commands/MuteCommand.java +++ b/src/main/java/com/loki/lochat/commands/MuteCommand.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.UUID; /** * Команда /mute nick [time] [-s] [причина] @@ -106,24 +107,15 @@ public class MuteCommand implements CommandExecutor, TabCompleter { } // Ищем игрока - Player target = Bukkit.getPlayer(targetName); - String finalTargetName = targetName; - java.util.UUID targetUUID; - - if (target == null) { - @SuppressWarnings("deprecation") - var offlinePlayer = Bukkit.getOfflinePlayer(targetName); - if (!offlinePlayer.hasPlayedBefore() && !offlinePlayer.isOnline()) { - sender.sendMessage(plugin.getMessageConfig().getComponent("errors.player-not-found")); - return true; - } - targetUUID = offlinePlayer.getUniqueId(); - finalTargetName = offlinePlayer.getName() != null ? offlinePlayer.getName() : targetName; - } else { - targetUUID = target.getUniqueId(); - finalTargetName = target.getName(); + UUID targetUUID = com.loki.lochat.utils.PlayerUtil.findPlayerUUID(targetName); + if (targetUUID == null) { + sender.sendMessage(plugin.getMessageConfig().getComponent("errors.player-not-found")); + return true; } + Player target = Bukkit.getPlayer(targetUUID); + String finalTargetName = com.loki.lochat.utils.PlayerUtil.getPlayerName(targetUUID); + // Проверяем, не замучен ли уже if (plugin.getMuteManager().isMuted(targetUUID)) { sender.sendMessage("§cИгрок уже замучен!"); diff --git a/src/main/java/com/loki/lochat/commands/MuteHistoryCommand.java b/src/main/java/com/loki/lochat/commands/MuteHistoryCommand.java index 78d2ceb..f61c58b 100644 --- a/src/main/java/com/loki/lochat/commands/MuteHistoryCommand.java +++ b/src/main/java/com/loki/lochat/commands/MuteHistoryCommand.java @@ -43,22 +43,12 @@ public class MuteHistoryCommand implements CommandExecutor, TabCompleter { } String targetName = args[0]; - UUID targetUUID = null; // Ищем игрока - Player target = Bukkit.getPlayer(targetName); - if (target != null) { - targetUUID = target.getUniqueId(); - } else { - // Пробуем найти оффлайн игрока - @SuppressWarnings("deprecation") - var offlinePlayer = Bukkit.getOfflinePlayer(targetName); - if (offlinePlayer.hasPlayedBefore() || offlinePlayer.isOnline()) { - targetUUID = offlinePlayer.getUniqueId(); - } else { - // Пробуем найти по имени в истории - targetUUID = plugin.getMuteManager().getUUIDByName(targetName); - } + UUID targetUUID = com.loki.lochat.utils.PlayerUtil.findPlayerUUID(targetName); + if (targetUUID == null) { + // Пробуем найти по имени в истории + targetUUID = plugin.getMuteManager().getUUIDByName(targetName); } if (targetUUID == null) { diff --git a/src/main/java/com/loki/lochat/commands/UnmuteCommand.java b/src/main/java/com/loki/lochat/commands/UnmuteCommand.java index 16ed65e..fb325c1 100644 --- a/src/main/java/com/loki/lochat/commands/UnmuteCommand.java +++ b/src/main/java/com/loki/lochat/commands/UnmuteCommand.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.UUID; /** * Команда /unmute nick [-s] @@ -57,24 +58,15 @@ public class UnmuteCommand implements CommandExecutor, TabCompleter { } // Ищем игрока - Player target = Bukkit.getPlayer(targetName); - String finalTargetName = targetName; - java.util.UUID targetUUID; - - if (target == null) { - @SuppressWarnings("deprecation") - var offlinePlayer = Bukkit.getOfflinePlayer(targetName); - if (!offlinePlayer.hasPlayedBefore() && !offlinePlayer.isOnline()) { - sender.sendMessage(plugin.getMessageConfig().getComponent("errors.player-not-found")); - return true; - } - targetUUID = offlinePlayer.getUniqueId(); - finalTargetName = offlinePlayer.getName() != null ? offlinePlayer.getName() : targetName; - } else { - targetUUID = target.getUniqueId(); - finalTargetName = target.getName(); + UUID targetUUID = com.loki.lochat.utils.PlayerUtil.findPlayerUUID(targetName); + if (targetUUID == null) { + sender.sendMessage(plugin.getMessageConfig().getComponent("errors.player-not-found")); + return true; } + Player target = Bukkit.getPlayer(targetUUID); + String finalTargetName = com.loki.lochat.utils.PlayerUtil.getPlayerName(targetUUID); + String operatorName = sender.getName(); // Размучиваем diff --git a/src/main/java/com/loki/lochat/config/ConfigManager.java b/src/main/java/com/loki/lochat/config/ConfigManager.java index 1da76bd..2813de7 100644 --- a/src/main/java/com/loki/lochat/config/ConfigManager.java +++ b/src/main/java/com/loki/lochat/config/ConfigManager.java @@ -154,7 +154,7 @@ public class ConfigManager { } public int getLocalRadius() { - return config.getInt("chat.local.radius", 100); + return config.getInt("chat.local.radius", com.loki.lochat.utils.Constants.DEFAULT_LOCAL_RADIUS); } public String getLocalPrefix() { diff --git a/src/main/java/com/loki/lochat/listeners/ChatListener.java b/src/main/java/com/loki/lochat/listeners/ChatListener.java index d100bec..f1830ae 100644 --- a/src/main/java/com/loki/lochat/listeners/ChatListener.java +++ b/src/main/java/com/loki/lochat/listeners/ChatListener.java @@ -81,60 +81,23 @@ public class ChatListener implements Listener { String processedPlain = PLAIN.serialize(processedMessage).trim(); if (processedPlain.isEmpty()) return; + // ===== FILTER ===== + processedMessage = applyMessageFilter(player, processedMessage, processedPlain); + if (processedMessage == null) return; // Сообщение заблокировано + + processedPlain = PLAIN.serialize(processedMessage); + // ===== COOLDOWN ===== - int cooldown = isGlobal - ? plugin.getConfigManager().getGlobalCooldown() - : plugin.getConfigManager().getLocalCooldown(); - - if (cooldown > 0 && !player.hasPermission("chat.bypass.cooldown")) { - if (plugin.getCooldownManager() - .isOnCooldown(player.getUniqueId(), chatType, cooldown)) { - - int remaining = plugin.getCooldownManager() - .getRemainingCooldown(player.getUniqueId(), chatType, cooldown); - - player.sendMessage( - plugin.getMessageConfig() - .getComponent("cooldown.wait", "{time}", String.valueOf(remaining)) - ); - return; - } - } + if (!checkCooldown(player, chatType)) return; // ===== ANTI SPAM ===== - if (!player.hasPermission("chat.bypass.antispam")) { - AntiSpamManager.SpamResult result = - plugin.getAntiSpamManager() - .checkMessage(player.getUniqueId(), processedPlain); - - switch (result) { - case TOO_MANY_CAPS -> { - player.sendMessage( - plugin.getMessageConfig().getComponent("antispam.caps") - ); - return; - } - case REPEAT_CHARS -> { - player.sendMessage( - plugin.getMessageConfig().getComponent("antispam.repeat") - ); - return; - } - case SIMILAR_MESSAGE -> { - player.sendMessage( - plugin.getMessageConfig().getComponent("antispam.similar") - ); - return; - } - case ALLOWED -> { - // Сообщение прошло проверку, продолжаем - } - } - } - + if (!checkAntiSpam(player, processedPlain)) return; plugin.getCooldownManager().setCooldown(player.getUniqueId(), chatType); + // ===== SPY ===== + plugin.getSpyManager().sendToSpies(player, processedMessage, isGlobal); + // ===== SEND ===== if (isGlobal) { plugin.getChatManager().sendGlobalMessage(player, processedMessage); @@ -143,6 +106,98 @@ public class ChatListener implements Listener { } } + private Component applyMessageFilter(Player player, Component message, String plainMessage) { + if (!plugin.getConfigManager().isFilterEnabled() || player.hasPermission("chat.bypass.filter")) { + return message; + } + + String filteredMessage = applyFilter(plainMessage); + if (!filteredMessage.equals(plainMessage)) { + String action = plugin.getConfigManager().getFilterAction(); + switch (action.toLowerCase()) { + case "block" -> { + player.sendMessage(plugin.getMessageConfig().getComponent("filter.blocked")); + return null; + } + case "warn" -> { + player.sendMessage(plugin.getMessageConfig().getComponent("filter.warning")); + return null; + } + case "censor" -> { + return Component.text(filteredMessage); + } + } + } + return message; + } + + private boolean checkCooldown(Player player, String chatType) { + int cooldown = chatType.equals("global") + ? plugin.getConfigManager().getGlobalCooldown() + : plugin.getConfigManager().getLocalCooldown(); + + if (cooldown > 0 && !player.hasPermission("chat.bypass.cooldown")) { + if (plugin.getCooldownManager().isOnCooldown(player.getUniqueId(), chatType, cooldown)) { + int remaining = plugin.getCooldownManager() + .getRemainingCooldown(player.getUniqueId(), chatType, cooldown); + + player.sendMessage( + plugin.getMessageConfig() + .getComponent("cooldown.wait", "{time}", String.valueOf(remaining)) + ); + return false; + } + } + return true; + } + + private boolean checkAntiSpam(Player player, String message) { + if (player.hasPermission("chat.bypass.antispam")) { + return true; + } + + AntiSpamManager.SpamResult result = plugin.getAntiSpamManager() + .checkMessage(player.getUniqueId(), message); + + switch (result) { + case TOO_MANY_CAPS -> { + player.sendMessage(plugin.getMessageConfig().getComponent("antispam.caps")); + return false; + } + case REPEAT_CHARS -> { + player.sendMessage(plugin.getMessageConfig().getComponent("antispam.repeat")); + return false; + } + case SIMILAR_MESSAGE -> { + player.sendMessage(plugin.getMessageConfig().getComponent("antispam.similar")); + return false; + } + case ALLOWED -> { + return true; + } + } + return true; + } + + private String applyFilter(String message) { + if (!plugin.getConfigManager().isFilterEnabled()) { + return message; + } + + String filtered = message; + String replacement = plugin.getConfigManager().getFilterReplacement(); + + for (String word : plugin.getConfigManager().getFilterWords()) { + if (word == null || word.trim().isEmpty()) continue; + + // Заменяем слово с учетом регистра и границ слов + String pattern = "(?i)\\b" + java.util.regex.Pattern.quote(word.trim()) + "\\b"; + filtered = filtered.replaceAll(pattern, replacement); + } + + return filtered; + } + @EventHandler public void onQuit(PlayerQuitEvent event) { Player player = event.getPlayer(); diff --git a/src/main/java/com/loki/lochat/managers/SpyManager.java b/src/main/java/com/loki/lochat/managers/SpyManager.java index 648c292..5607a57 100644 --- a/src/main/java/com/loki/lochat/managers/SpyManager.java +++ b/src/main/java/com/loki/lochat/managers/SpyManager.java @@ -46,6 +46,25 @@ public class SpyManager { } } + public void sendToSpies(Player sender, net.kyori.adventure.text.Component message, boolean isGlobal) { + if (spyEnabled.isEmpty()) return; + + String chatType = isGlobal ? "Global" : "Local"; + String plainMessage = net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer.plainText().serialize(message); + String format = plugin.getMessageConfig().get("spy.chat-format", + "§7[SPY] §e{type} §7{sender}: §f{message}"); + + for (UUID spyUuid : spyEnabled) { + Player spy = Bukkit.getPlayer(spyUuid); + if (spy != null && spy.isOnline() && !spy.equals(sender)) { + spy.sendMessage(ChatFormatter.parse(format + .replace("{type}", chatType) + .replace("{sender}", sender.getName()) + .replace("{message}", plainMessage))); + } + } + } + public void removeSpy(UUID player) { spyEnabled.remove(player); } diff --git a/src/main/java/com/loki/lochat/utils/Constants.java b/src/main/java/com/loki/lochat/utils/Constants.java new file mode 100644 index 0000000..dfe05e6 --- /dev/null +++ b/src/main/java/com/loki/lochat/utils/Constants.java @@ -0,0 +1,31 @@ +package com.loki.lochat.utils; + +/** + * Константы плагина + */ +public final class Constants { + + private Constants() {} + + // Чат + public static final int DEFAULT_LOCAL_RADIUS = 100; + public static final int CLEAR_CHAT_LINES = 100; + + // Время + public static final long MILLIS_IN_SECOND = 1000L; + public static final int SECONDS_IN_MINUTE = 60; + public static final int MINUTES_IN_HOUR = 60; + public static final int HOURS_IN_DAY = 24; + + // Градиенты + public static final int DEFAULT_PRICE_PER_COLOR = 50; + public static final int DEFAULT_PREFIX_PRICE = 500; + public static final int LUCKPERMS_PREFIX_PRIORITY = 100; + + // Folia/Paper совместимость + public static final int TICKS_PER_SECOND = 20; + public static final int MILLIS_PER_TICK = 50; + + // Анти-спам + public static final int PERCENTAGE_MULTIPLIER = 100; +} \ No newline at end of file diff --git a/src/main/java/com/loki/lochat/utils/PlayerUtil.java b/src/main/java/com/loki/lochat/utils/PlayerUtil.java new file mode 100644 index 0000000..655d1f0 --- /dev/null +++ b/src/main/java/com/loki/lochat/utils/PlayerUtil.java @@ -0,0 +1,70 @@ +package com.loki.lochat.utils; + +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +import java.util.UUID; + +/** + * Утилиты для работы с игроками + */ +public final class PlayerUtil { + + private PlayerUtil() {} + + /** + * Находит игрока по имени (онлайн или оффлайн) + * @param name имя игрока + * @return UUID игрока или null если не найден + */ + public static UUID findPlayerUUID(String name) { + // Сначала ищем онлайн игрока + Player onlinePlayer = Bukkit.getPlayer(name); + if (onlinePlayer != null) { + return onlinePlayer.getUniqueId(); + } + + // Затем ищем оффлайн игрока + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(name); + if (offlinePlayer.hasPlayedBefore() || offlinePlayer.isOnline()) { + return offlinePlayer.getUniqueId(); + } + + return null; + } + + /** + * Проверяет, существует ли игрок (играл на сервере) + * @param name имя игрока + * @return true если игрок существует + */ + public static boolean playerExists(String name) { + return findPlayerUUID(name) != null; + } + + /** + * Получает имя игрока по UUID + * @param uuid UUID игрока + * @return имя игрока или null + */ + public static String getPlayerName(UUID uuid) { + Player onlinePlayer = Bukkit.getPlayer(uuid); + if (onlinePlayer != null) { + return onlinePlayer.getName(); + } + + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); + return offlinePlayer.getName(); + } + + /** + * Проверяет, онлайн ли игрок + * @param uuid UUID игрока + * @return true если игрок онлайн + */ + public static boolean isPlayerOnline(UUID uuid) { + Player player = Bukkit.getPlayer(uuid); + return player != null && player.isOnline(); + } +} \ No newline at end of file diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml index f148fab..6d09ec2 100644 --- a/src/main/resources/messages.yml +++ b/src/main/resources/messages.yml @@ -39,10 +39,11 @@ spy: enabled: "CADFШпион режим включен" disabled: "CADFШпион режим выключен" format: "󅒐[SPY] {sender} → {receiver}: {message}" + chat-format: "󅒐[SPY] {type} {sender}: {message}" filter: blocked: "CADFСообщение заблокировано (мат)" - warned: "CADFПредупреждение: не используйте мат!" + warning: "CADFПредупреждение: не используйте мат!" cooldown: wait: "CADFПодождите {time} сек перед следующим сообщением"