Skip to content

敏感词过滤 Skill ​

硬规则 ​

  • 玩家产生且会被其他玩家看到、保存或转发的文本,必须先在服务端调用 Game.FilterSensitiveWords。
  • 不要依赖客户端过滤。客户端只能用于即时提示,服务端结果才可作为后续广播、持久化或跨服转发的输入。
  • ServerChannel 是服务端之间的发布/订阅消息传输机制。channel 是消息主题或路由标识,不是玩家聊天房间;载荷不会被自动检查或过滤。
  • 使用 ServerChannelMessage.Publish / PublishToUser 开发跨服聊天时,先过滤玩家文本,再构造和发送消息。
  • DualEndEvent、TypedMessage、ProtoCustomMessage 同样只负责传输,不自动过滤玩家文本。
  • 不要把 WasFiltered == false 当成服务可用性判定。它只表示本次没有发生替换。
  • 不要在日志、云数据、排行榜、邮件、频道消息或审计事件中继续使用过滤前的玩家文本,除非项目有明确且合规的受控审计方案。

服务端处理顺序 ​

  1. 校验发送者身份、权限、频率、空文本和长度。
  2. 调用 Game.FilterSensitiveWords(input)。
  3. 按产品策略选择替换或拒绝。
  4. 仅使用 FilteredText 广播、持久化或跨服发送。
  5. 客户端只显示服务端确认后的文本。
csharp
#if SERVER
var result = Game.FilterSensitiveWords(playerText);

// 替换策略:继续发送已过滤文本。
var safeText = result.FilteredText;

// 拒绝策略:命中时停止提交,并向客户端返回项目定义的提示。
if (result.WasFiltered)
{
    return false;
}
#endif

ServerChannel 边界 ​

下面的写法不会触发任何自动内容审核:

csharp
ServerChannelMessage.PublishToUser(targetUserId, "private-message", payload);

如果 payload 包含玩家文本,应在来源服务器先过滤:

csharp
#if SERVER
var filterResult = Game.FilterSensitiveWords(input);
var payload = new CrossServerChatMessage
{
    SenderUserId = senderUserId,
    Content = filterResult.FilteredText
};

ServerChannelMessage.PublishToUser(targetUserId, "private-message", payload);
#endif

接收端如果可能收到旧版本服务器或其他未受信任来源的消息,可在展示给玩家前再次过滤。不要把消息主题名包含 chat 误认为系统会识别聊天语义。

审查清单 ​

  • [ ] 玩家文本在服务端过滤,而不是只在客户端过滤
  • [ ] 广播、存储和跨服发送使用 FilteredText
  • [ ] 昵称、公会名、房间名和留言等非聊天文本也纳入检查
  • [ ] ServerChannel 代码没有假设传输层会自动过滤
  • [ ] 已处理长度、频率、权限和重复发送;敏感词过滤不是完整的反滥用系统
  • [ ] 没有把过滤前文本写入普通日志或不受控存储

相关文档 ​

  • docs/systems/SensitiveWordFilterSystem.md
  • docs/systems/ServerChannelSystem.md
  • docs/systems/DualEndEventSystem.md