Skip to content

Commit

Permalink
v2.3.0 支持将玩家消息转换为系统消息
Browse files Browse the repository at this point in the history
  • Loading branch information
ApliNi committed Feb 13, 2024
1 parent 7d972ec commit 695b425
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 31 deletions.
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,13 @@ dev:
# 是否对输入的 JSON 进行序列化, 修改它可能影响现有的配置
# CreatePacket = 使用 protocolLib 创建新数据包再解析, 这没有意义
# ComponentSerializer = 这会使 JSON 内部的顺序发生变化, 并可能丢失部分原版消息
# NONE = 不进行序列化
# NONE = 不进行序列化
serializedInput: NONE
# 将玩家消息转换为系统消息
# Convert = 转换消息并进行替换
# ConvertBypass = 转换消息并绕过替换
# NONE = 禁用此功能
convertPlayerMessages: NONE

list: # 替换列表

Expand Down Expand Up @@ -64,13 +69,13 @@ list: # 替换列表
# [可选] 仅对拥有该权限的玩家处理这条消息, 默认所有玩家
- permission: 'minecraft.command'
# [必选] 检查消息长度是否在此区间内
# [50, 64] = 大于等于50且小于等于64
# [50, 64] = 大于等于 50 且小于等于 64
# [64] = 等于 64
inspectLength: [50, 64]
# [必选] 使用正则表达式匹配
get: '^\{"text":"","extra":\["Missing required argument (\d+)"\]\}$'
# [必选] 将消息替换为
# _$1_ = 正则匹配到的变量 1, 也可以是 `_$2_` (第 2 个变量)...
# _$1_ = 正则匹配到的变量 1, 也可以是 _$2_ (第 2 个变量)...
# _$1:ItemType_ = 将 _$1_ 用于获取物品类型, 提供给 JSON hoverEvent 使用的物品类型 show_entity, show_item(block)
# _$1:TranslatedName_ = 将 _$1_ 用于名称翻译, 返回与语言路径对应的 KEY, 例如 `entity.minecraft.allay`
# _$1:Words:组名_ = 将 _$1_ 用于词替换, 需要配置 words.yml
Expand All @@ -91,8 +96,8 @@ list: # 替换列表
displayObject: ''
# [可选] 继承和其他配置. 将多个配置合并为组, 同时处理来提高性能
# LINK = 与下一条配置合并为组, 将此配置处理完毕的内容传递给下一条配置, 请确保存在下一条配置
# LINK_SER = 使 GROUP 传递序列化后的 JSON 文本
# CLOSE = 如果匹配, 则立即退出匹配检查循环, 不再处理任何数据
# LINK_SER = 使 LINK 传递序列化后的 JSON 文本, 需要开启序列化功能
# CLOSE = 如果匹配, 则停止处理这条消息, 可用于排除一些被高频发送的消息
inherit: ''

```
Expand Down
24 changes: 19 additions & 5 deletions README_MCBBS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ https://github.com/ApliNi/useTranslatedNames

---

## useTranslatedNames
内置获取翻译名功能的JSON字符串替换插件, 可用于消息替换和翻译 CoreProtect 等插件的消息

![](https://github.com/ApliNi/useTranslatedNames/blob/main/_img/%E6%95%88%E6%9E%9C%E5%9B%BE.png)

下载: https://modrinth.com/plugin/usetranslatednames

---

## 功能和指令
- `/utn` 显示插件信息和统计数据
- `/utn json <JSON>` - 测试 JSON 字符串
Expand All @@ -37,8 +46,13 @@ dev:
# 是否对输入的 JSON 进行序列化, 修改它可能影响现有的配置
# CreatePacket = 使用 protocolLib 创建新数据包再解析, 这没有意义
# ComponentSerializer = 这会使 JSON 内部的顺序发生变化, 并可能丢失部分原版消息
# NONE = 不进行序列化
# NONE = 不进行序列化
serializedInput: NONE
# 将玩家消息转换为系统消息
# Convert = 转换消息并进行替换
# ConvertBypass = 转换消息并绕过替换
# NONE = 禁用此功能
convertPlayerMessages: NONE

list: # 替换列表

Expand Down Expand Up @@ -70,13 +84,13 @@ list: # 替换列表
# [可选] 仅对拥有该权限的玩家处理这条消息, 默认所有玩家
- permission: 'minecraft.command'
# [必选] 检查消息长度是否在此区间内
# [50, 64] = 大于等于50且小于等于64
# [50, 64] = 大于等于 50 且小于等于 64
# [64] = 等于 64
inspectLength: [50, 64]
# [必选] 使用正则表达式匹配
get: '^\{"text":"","extra":\["Missing required argument (\d+)"\]\}$'
# [必选] 将消息替换为
# _$1_ = 正则匹配到的变量 1, 也可以是 `_$2_` (第 2 个变量)...
# _$1_ = 正则匹配到的变量 1, 也可以是 _$2_ (第 2 个变量)...
# _$1:ItemType_ = 将 _$1_ 用于获取物品类型, 提供给 JSON hoverEvent 使用的物品类型 show_entity, show_item(block)
# _$1:TranslatedName_ = 将 _$1_ 用于名称翻译, 返回与语言路径对应的 KEY, 例如 `entity.minecraft.allay`
# _$1:Words:组名_ = 将 _$1_ 用于词替换, 需要配置 words.yml
Expand All @@ -97,8 +111,8 @@ list: # 替换列表
displayObject: ''
# [可选] 继承和其他配置. 将多个配置合并为组, 同时处理来提高性能
# LINK = 与下一条配置合并为组, 将此配置处理完毕的内容传递给下一条配置, 请确保存在下一条配置
# LINK_SER = 使 GROUP 传递序列化后的 JSON 文本
# CLOSE = 如果匹配, 则立即退出匹配检查循环, 不再处理任何数据
# LINK_SER = 使 LINK 传递序列化后的 JSON 文本, 需要开启序列化功能
# CLOSE = 如果匹配, 则停止处理这条消息, 可用于排除一些被高频发送的消息
inherit: ''

```
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>io.github.aplini</groupId>
<artifactId>useTranslatedNames</artifactId>
<version>2.2.0</version>
<version>2.3.0</version>

<name>useTranslatedNames</name>

Expand Down
3 changes: 3 additions & 0 deletions src/main/java/aplini/usetranslatednames/Enum/Key.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ public enum Key {
GetStrings,
CreatePacket,
ComponentSerializer,
Convert,
ConvertBypass,
NONE,
}
7 changes: 5 additions & 2 deletions src/main/java/aplini/usetranslatednames/Enum/Status.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package aplini.usetranslatednames.Enum;

public class Status {
public long Messages = 0;
public long Matches = 0;
// 消息总数
public long MsgCount = 0;
// 成功匹配次数
public long MatchesCount = 0;
// 总计耗时
public double TotalTime = 0;
}
80 changes: 67 additions & 13 deletions src/main/java/aplini/usetranslatednames/UseTranslatedNames.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
import org.bukkit.command.TabExecutor;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.plugin.java.JavaPlugin;

import java.io.File;
Expand All @@ -34,6 +37,8 @@

public final class UseTranslatedNames extends JavaPlugin implements CommandExecutor, TabExecutor, Listener {

public static UseTranslatedNames plugin;

// 用户配置版本
public static int _configVersion;
// 解析器模式
Expand All @@ -48,31 +53,48 @@ public final class UseTranslatedNames extends JavaPlugin implements CommandExecu
int listSize = 0;

// 调试模式
private int _debug = 0;
public static int _debug = 0;

// 记录统计信息
Status status = new Status();
static Status status = new Status();

// 用于静默发送聊天消息, 绕过消息监听器
private ProtocolManager protocolManager;
public static ProtocolManager protocolManager;


@Override
public void onEnable() {
plugin = this;
loadConfig();
Util.load(this);

// bStats
if(getConfig().getBoolean("bStats", true)){
new Metrics(this, 20766);
}
// 收集一些性能数据和消息总数
Metrics metrics = new Metrics(this, 20766);
// 平均消息延迟
metrics.addCustomChart(new Metrics.SimplePie("AverageTime", () -> {
double TotalTime = status.TotalTime / 1_000_000.0;
double AverageTime = TotalTime / status.MsgCount;
return String.format("%.2f", AverageTime) +"ms";
}));
// 其他统计信息
// metrics.addCustomChart(new Metrics.MultiLineChart("Status", () -> {
// Map<String, Integer> map = new HashMap<>();
// map.put("NumberOfMessages", Math.toIntExact(status.MsgCount));
// map.put("NumberOfMatches", Math.toIntExact(status.MatchesCount));
// map.put("NumberOfTotalTime", Math.toIntExact(Math.round(status.TotalTime / 1e9)));
// return map;
// }));
metrics.addCustomChart(new Metrics.SingleLineChart("MsgCount", () -> Math.toIntExact(status.MsgCount)));
metrics.addCustomChart(new Metrics.SingleLineChart("MatchesCount", () -> Math.toIntExact(status.MatchesCount)));
metrics.addCustomChart(new Metrics.SingleLineChart("TotalTime", () -> Math.toIntExact(Math.round(status.TotalTime / 1e9))));

// 注册指令
Objects.requireNonNull(getCommand("utn")).setExecutor(this);

// 用于静默发送聊天消息, 绕过消息监听器
protocolManager = ProtocolLibrary.getProtocolManager();


// 添加一个数据包监听器
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(this,
ListenerPriority.LOW, // 监听器优先级
Expand Down Expand Up @@ -114,7 +136,7 @@ public void onPacketSending(PacketEvent event){
}

// 记录运行时间
status.Messages ++;
status.MsgCount++;
status.TotalTime += System.nanoTime() - _startTime;
}
});
Expand Down Expand Up @@ -169,7 +191,7 @@ public boolean runJsonTestReplaceConfig(PacketEvent event, Player player, String
Matcher matcher = cli.regExp.matcher(jsonTest);
while(matcher.find()){

status.Matches ++;
status.MatchesCount++;

if(_debug >= 4){
getLogger().info(" - [HIT]");
Expand Down Expand Up @@ -418,10 +440,42 @@ public long loadConfig(){
}
listSize = list.size();

// 配置玩家消息监听器
onPlayerChat.mode = switch(getConfig().getString("dev.convertPlayerMessages", "NONE")){
case "Convert" -> Key.Convert;
case "ConvertBypass" -> Key.ConvertBypass;
default -> Key.NONE;
};
// 注册和注销监听器
if(onPlayerChat.mode == Key.NONE){
if(onPlayerChat.func != null){
HandlerList.unregisterAll(onPlayerChat.func);
onPlayerChat.func = null;
}
}else{
if(onPlayerChat.func == null){
onPlayerChat.func = new onPlayerChat();
getServer().getPluginManager().registerEvents(onPlayerChat.func, this);
}
}

return Math.round((System.nanoTime() - _startTime) / 1_000_000.0);
}


@EventHandler
public void onPlayerChat(AsyncPlayerChatEvent event){
String message = event.getMessage();

// 在这里处理玩家发送的消息
// 你可以根据需要进行逻辑处理或条件检查

// 示例:将玩家发送的消息改为大写
String upperCaseMessage = message.toUpperCase();
event.setMessage(upperCaseMessage);
}


@Override // 指令补全
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
if(args.length == 1){
Expand All @@ -443,10 +497,10 @@ public List<String> onTabComplete(CommandSender sender, Command command, String
return null;
}
@Override // 执行指令
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
public boolean onCommand(CommandSender sender, Command command, String label, String[] args){

double TotalTime = status.TotalTime / 1_000_000.0;
double AverageTime = TotalTime / status.Messages;
double AverageTime = TotalTime / status.MsgCount;

// 默认输出插件信息
if(args.length == 0){
Expand All @@ -458,8 +512,8 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
" - /utn reload - 重载配置\n"+
" - /utn debug [Level] - 调试模式\n"+
" 统计信息:\n"+
" - 监听消息: "+ status.Messages +"\n"+
" - 成功匹配: "+ status.Matches +"\n"+
" - 监听消息: "+ status.MsgCount +"\n"+
" - 成功匹配: "+ status.MatchesCount +"\n"+
" - 平均延迟: "+ String.format("%.2f", AverageTime) +" ms [累计: "+ String.format("%.2f", TotalTime) +" ms]\n"
);
return true;
Expand Down
60 changes: 60 additions & 0 deletions src/main/java/aplini/usetranslatednames/onPlayerChat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package aplini.usetranslatednames;

import aplini.usetranslatednames.Enum.Key;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;

import java.util.concurrent.CompletableFuture;

import static aplini.usetranslatednames.UseTranslatedNames.*;

public class onPlayerChat implements Listener {

static onPlayerChat func = null;
static Key mode;

@EventHandler(priority = EventPriority.HIGHEST)
public void onAsyncPlayerChatEvent(AsyncPlayerChatEvent event){
// 取消发送消息
event.setCancelled(true);

CompletableFuture.runAsync(() -> {

Player player = event.getPlayer();
// 获取已格式化的消息
String msg = String.format(event.getFormat(), player.getName(), event.getMessage());

if(_debug >= 1){
plugin.getLogger().info("");
plugin.getLogger().info("");
plugin.getLogger().info("[DEBUG] [PlayerChat] [Player: "+ event.getPlayer().getName() +
", Lang: "+ player.getLocale() +"] [Length: "+ msg.length() +"], [MODE: "+ mode.toString() +"]");
if(_debug >= 2){
plugin.getLogger().info(" - [FORMAT]: "+ event.getFormat());
plugin.getLogger().info(" - [MSG]: "+ event.getMessage());
plugin.getLogger().info(" - [GET]: "+ msg);
}
}
Bukkit.getConsoleSender().sendMessage(msg);
switch(mode){
case Convert -> Bukkit.spigot().broadcast(new TextComponent(msg));
case ConvertBypass -> {
// 静默发送消息给每个玩家
PacketContainer chatPacket = protocolManager.createPacket(PacketType.Play.Server.SYSTEM_CHAT);
chatPacket.getChatComponents().write(0, WrappedChatComponent.fromText(msg));
for(Player li : Bukkit.getOnlinePlayers()){
protocolManager.sendServerPacket(li, chatPacket, false);
}
}
}
});
}
}
15 changes: 10 additions & 5 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ dev:
# 是否对输入的 JSON 进行序列化, 修改它可能影响现有的配置
# CreatePacket = 使用 protocolLib 创建新数据包再解析, 这没有意义
# ComponentSerializer = 这会使 JSON 内部的顺序发生变化, 并可能丢失部分原版消息
# NONE = 不进行序列化
# NONE = 不进行序列化
serializedInput: NONE
# 将玩家消息转换为系统消息
# Convert = 转换消息并进行替换
# ConvertBypass = 转换消息并绕过替换
# NONE = 禁用此功能
convertPlayerMessages: NONE

list: # 替换列表

Expand Down Expand Up @@ -44,13 +49,13 @@ list: # 替换列表
# [可选] 仅对拥有该权限的玩家处理这条消息, 默认所有玩家
- permission: 'minecraft.command'
# [必选] 检查消息长度是否在此区间内
# [50, 64] = 大于等于50且小于等于64
# [50, 64] = 大于等于 50 且小于等于 64
# [64] = 等于 64
inspectLength: [50, 64]
# [必选] 使用正则表达式匹配
get: '^\{"text":"","extra":\["Missing required argument (\d+)"\]\}$'
# [必选] 将消息替换为
# _$1_ = 正则匹配到的变量 1, 也可以是 `_$2_` (第 2 个变量)...
# _$1_ = 正则匹配到的变量 1, 也可以是 _$2_ (第 2 个变量)...
# _$1:ItemType_ = 将 _$1_ 用于获取物品类型, 提供给 JSON hoverEvent 使用的物品类型 show_entity, show_item(block)
# _$1:TranslatedName_ = 将 _$1_ 用于名称翻译, 返回与语言路径对应的 KEY, 例如 `entity.minecraft.allay`
# _$1:Words:组名_ = 将 _$1_ 用于词替换, 需要配置 words.yml
Expand All @@ -71,6 +76,6 @@ list: # 替换列表
displayObject: ''
# [可选] 继承和其他配置. 将多个配置合并为组, 同时处理来提高性能
# LINK = 与下一条配置合并为组, 将此配置处理完毕的内容传递给下一条配置, 请确保存在下一条配置
# LINK_SER = 使 GROUP 传递序列化后的 JSON 文本
# CLOSE = 如果匹配, 则立即退出匹配检查循环, 不再处理任何数据
# LINK_SER = 使 LINK 传递序列化后的 JSON 文本, 需要开启序列化功能
# CLOSE = 如果匹配, 则停止处理这条消息, 可用于排除一些被高频发送的消息
inherit: ''

0 comments on commit 695b425

Please sign in to comment.