Merge branch 'zesterer/automod' into 'master'

Relaxed automod somewhat

See merge request veloren/veloren!3559
This commit is contained in:
Joshua Barretto 2022-08-23 09:44:54 +00:00
commit 69e5c1424f
3 changed files with 44 additions and 6 deletions

View File

@ -146,6 +146,25 @@ impl<G> ChatType<G> {
ChatType::Meta => None, ChatType::Meta => None,
} }
} }
/// `None` means that the chat type is automated.
pub fn is_private(&self) -> Option<bool> {
match self {
ChatType::Online(_)
| ChatType::Offline(_)
| ChatType::CommandInfo
| ChatType::CommandError
| ChatType::FactionMeta(_)
| ChatType::GroupMeta(_)
| ChatType::Npc(_, _)
| ChatType::NpcSay(_, _)
| ChatType::NpcTell(_, _, _)
| ChatType::Meta
| ChatType::Kill(_, _) => None,
ChatType::Tell(_, _) | ChatType::Group(_, _) | ChatType::Faction(_, _) => Some(true),
ChatType::Say(_) | ChatType::Region(_) | ChatType::World(_) => Some(false),
}
}
} }
// Stores chat text, type // Stores chat text, type

View File

@ -1,7 +1,7 @@
use crate::settings::ModerationSettings; use crate::settings::ModerationSettings;
use authc::Uuid; use authc::Uuid;
use censor::Censor; use censor::Censor;
use common::comp::AdminRole; use common::comp::{AdminRole, ChatType, Group};
use hashbrown::HashMap; use hashbrown::HashMap;
use std::{ use std::{
fmt, fmt,
@ -95,12 +95,18 @@ impl AutoMod {
player: Uuid, player: Uuid,
role: Option<AdminRole>, role: Option<AdminRole>,
now: Instant, now: Instant,
chat_type: &ChatType<Group>,
msg: &str, msg: &str,
) -> Result<Option<ActionNote>, ActionErr> { ) -> Result<Option<ActionNote>, ActionErr> {
// TODO: Consider using grapheme cluster count instead of size in bytes // TODO: Consider using grapheme cluster count instead of size in bytes
if msg.len() > MAX_BYTES_CHAT_MSG { if msg.len() > MAX_BYTES_CHAT_MSG {
Err(ActionErr::TooLong) Err(ActionErr::TooLong)
} else if !self.settings.automod || (role.is_some() && self.settings.admins_exempt) { } else if !self.settings.automod
// Is this a private chat message?
|| chat_type.is_private().unwrap_or(true)
// Is the user exempt from automoderation?
|| (role.is_some() && self.settings.admins_exempt)
{
Ok(None) Ok(None)
} else if self.censor.check(msg) { } else if self.censor.check(msg) {
Err(ActionErr::BannedWord) Err(ActionErr::BannedWord)
@ -123,7 +129,7 @@ impl AutoMod {
const CHAT_VOLUME_PERIOD: f32 = 30.0; const CHAT_VOLUME_PERIOD: f32 = 30.0;
/// The maximum permitted average number of chat messages over the chat volume /// The maximum permitted average number of chat messages over the chat volume
/// period. /// period.
const MAX_AVG_MSG_PER_SECOND: f32 = 1.0 / 7.0; // No more than a message every 7 seconds on average const MAX_AVG_MSG_PER_SECOND: f32 = 1.0 / 5.0; // No more than a message every 5 seconds on average
/// The period for which a player should be muted when they exceed the message /// The period for which a player should be muted when they exceed the message
/// spam threshold. /// spam threshold.
const SPAM_MUTE_PERIOD: Duration = Duration::from_secs(180); const SPAM_MUTE_PERIOD: Duration = Duration::from_secs(180);

View File

@ -114,7 +114,12 @@ pub trait StateExt {
/// Performed after loading component data from the database /// Performed after loading component data from the database
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents); fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents);
/// Iterates over registered clients and send each `ServerMsg` /// Iterates over registered clients and send each `ServerMsg`
fn validate_chat_msg(&self, player: EcsEntity, msg: &str) -> bool; fn validate_chat_msg(
&self,
player: EcsEntity,
chat_type: &comp::ChatType<comp::Group>,
msg: &str,
) -> bool;
fn send_chat(&self, msg: comp::UnresolvedChatMsg); fn send_chat(&self, msg: comp::UnresolvedChatMsg);
fn notify_players(&self, msg: ServerGeneral); fn notify_players(&self, msg: ServerGeneral);
fn notify_in_game_clients(&self, msg: ServerGeneral); fn notify_in_game_clients(&self, msg: ServerGeneral);
@ -676,7 +681,12 @@ impl StateExt for State {
} }
} }
fn validate_chat_msg(&self, entity: EcsEntity, msg: &str) -> bool { fn validate_chat_msg(
&self,
entity: EcsEntity,
chat_type: &comp::ChatType<comp::Group>,
msg: &str,
) -> bool {
let mut automod = self.ecs().write_resource::<AutoMod>(); let mut automod = self.ecs().write_resource::<AutoMod>();
let Some(client) = self.ecs().read_storage::<Client>().get(entity) else { return true }; let Some(client) = self.ecs().read_storage::<Client>().get(entity) else { return true };
let Some(player) = self.ecs().read_storage::<Player>().get(entity) else { return true }; let Some(player) = self.ecs().read_storage::<Player>().get(entity) else { return true };
@ -688,6 +698,7 @@ impl StateExt for State {
.get(entity) .get(entity)
.map(|a| a.0), .map(|a| a.0),
Instant::now(), Instant::now(),
chat_type,
msg, msg,
) { ) {
Ok(note) => { Ok(note) => {
@ -727,7 +738,9 @@ impl StateExt for State {
if msg.chat_type.uid().map_or(true, |sender| { if msg.chat_type.uid().map_or(true, |sender| {
(*ecs.read_resource::<UidAllocator>()) (*ecs.read_resource::<UidAllocator>())
.retrieve_entity_internal(sender.0) .retrieve_entity_internal(sender.0)
.map_or(false, |e| self.validate_chat_msg(e, &msg.message)) .map_or(false, |e| {
self.validate_chat_msg(e, &msg.chat_type, &msg.message)
})
}) { }) {
match &msg.chat_type { match &msg.chat_type {
comp::ChatType::Offline(_) comp::ChatType::Offline(_)