Add Speaking Frequency Limit

This commit is contained in:
2023-01-12 20:34:07 +08:00
parent d0bd6921d9
commit 435bcd1cb4
5 changed files with 51 additions and 27 deletions

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>

View File

@ -9,9 +9,8 @@ Talking to the server account in the game is equivalent to sending to the world
## TODO List ## TODO List
- [x] Chat between players - [x] Chat between players
- [x] Chat management commands - [x] Chat management commands
- [ ] Chat speech limit - [x] Speaking Frequency Limit
- [ ] Chat Moderation - [ ] Chat Moderation
- [ ] Console talk
- [ ] Chat api _(~~OneBot api~~)_ - [ ] Chat api _(~~OneBot api~~)_
- [ ] ... - [ ] ...

View File

@ -9,9 +9,8 @@
## TODO List ## TODO List
- [x] 玩家间聊天 - [x] 玩家间聊天
- [x] 聊天管理命令 - [x] 聊天管理命令
- [ ] 发言间隔限制 - [x] 发言频率限制
- [ ] 聊天内容审查 - [ ] 聊天内容审查
- [ ] 控制台发言(运维用)
- [ ] 聊天api _(~~OneBot api~~)_ - [ ] 聊天api _(~~OneBot api~~)_
- [ ] ... - [ ] ...

View File

@ -29,7 +29,6 @@ import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Date;
public final class OpenChatPlugin extends Plugin { public final class OpenChatPlugin extends Plugin {
private static OpenChatPlugin instance; private static OpenChatPlugin instance;
@ -122,14 +121,4 @@ public final class OpenChatPlugin extends Plugin {
saveData(); saveData();
getLogger().info("[OpenChat] Disabled."); getLogger().info("[OpenChat] Disabled.");
} }
/**
* 更新禁言列表清理所有解除禁言用户
*/
public void updateBanList() {
if (getData().banList.isEmpty())
return;
var now = new Date();
getData().banList.entrySet().removeIf(entry -> entry.getValue().before(now));
}
} }

View File

@ -3,6 +3,11 @@ package com.github.jie65535.openchat;
import emu.grasscutter.GameConstants; import emu.grasscutter.GameConstants;
import emu.grasscutter.game.chat.ChatSystem; import emu.grasscutter.game.chat.ChatSystem;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue;
import java.util.Date;
public class OpenChatSystem extends ChatSystem { public class OpenChatSystem extends ChatSystem {
private final OpenChatPlugin plugin; private final OpenChatPlugin plugin;
@ -39,19 +44,30 @@ public class OpenChatSystem extends ChatSystem {
if (!plugin.getConfig().serverChatEnabled) { if (!plugin.getConfig().serverChatEnabled) {
return; return;
} }
// 刷新列表
plugin.updateBanList();
// 检测是否正在禁言中 // 检测是否正在禁言中
if (plugin.getData().banList.containsKey(player.getUid())) { if (checkIsBanning(player)) {
return;
}
// 处理发言频率限制与发言内容审查
if (!checkMessageFre(player) || !checkMessageModeration(message)) {
// 可提示也可忽略忽略可让玩家以为自己发送成功其实别人看不到 // 可提示也可忽略忽略可让玩家以为自己发送成功其实别人看不到
plugin.getLogger().warn(String.format("Message blocked: player=%s(%d): \"%s\"", plugin.getLogger().warn(String.format("Message blocked (banning): player=%s(%d): \"%s\"",
player.getNickname(), player.getUid(), message)); player.getNickname(), player.getUid(), message));
return; return;
} }
// 处理发言频率限制
if (!checkMessageFre(player)) {
// 可提示也可忽略忽略可让玩家以为自己发送成功其实别人看不到
plugin.getLogger().warn(String.format("Message blocked (too often): player=%s(%d): \"%s\"",
player.getNickname(), player.getUid(), message));
return;
}
// 处理发言内容审查
if (!checkMessageModeration(message)) {
plugin.getLogger().warn(String.format("Message blocked (moderation): player=%s(%d): \"%s\"",
player.getNickname(), player.getUid(), message));
return;
}
// 格式化消息 // 格式化消息
message = OpenChatPlugin.getInstance().getConfig().serverChatFormat message = OpenChatPlugin.getInstance().getConfig().serverChatFormat
.replace("{nickName}", player.getNickname()) .replace("{nickName}", player.getNickname())
@ -66,23 +82,43 @@ public class OpenChatSystem extends ChatSystem {
} }
} }
private boolean checkIsBanning(Player player) {
var banList = plugin.getData().banList;
// 检测是否正在禁言中
if (banList.containsKey(player.getUid())) {
if (banList.get(player.getUid()).before(new Date())) {
banList.remove(player.getUid());
} else {
return true;
}
}
return false;
}
/** /**
* 消息内容审查 * 消息内容审查
* @param message 消息 * @param message 消息
* @return 是否合法合规 * @return 是否合法合规
*/ */
private boolean checkMessageModeration(String message) { private boolean checkMessageModeration(String message) {
// TODO // TODO see https://github.com/houbb/sensitive-word
return true; return !message.isEmpty();
} }
Int2ObjectMap<LongArrayFIFOQueue> speakingTimes = new Int2ObjectOpenHashMap<>();
/** /**
* 消息频率检查 * 消息频率检查
* @param player 玩家对象 * @param player 玩家对象
* @return 是否在约定阈值内 * @return 是否在约定阈值内
*/ */
private boolean checkMessageFre(Player player) { private boolean checkMessageFre(Player player) {
// TODO var list = speakingTimes.computeIfAbsent(player.getUid(), i -> new LongArrayFIFOQueue());
return true; var now = System.currentTimeMillis();
list.enqueue(now);
var t = now - 60_000;
while (list.firstLong() < t)
list.dequeueLong();
return list.size() <= plugin.getConfig().messageFreLimitPerMinute;
} }
} }