mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
initial approach of utelising chat-i18n crate by chat-cli bot
This commit is contained in:
parent
a0ef3be9ac
commit
cc3fcfce8c
13
Cargo.lock
generated
13
Cargo.lock
generated
@ -6683,6 +6683,8 @@ dependencies = [
|
||||
"veloren-common-state",
|
||||
"veloren-common-systems",
|
||||
"veloren-network",
|
||||
"veloren-voxygen-chat-i18n",
|
||||
"veloren-voxygen-i18n",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -7089,6 +7091,7 @@ dependencies = [
|
||||
"veloren-common-systems",
|
||||
"veloren-server",
|
||||
"veloren-voxygen-anim",
|
||||
"veloren-voxygen-chat-i18n",
|
||||
"veloren-voxygen-egui",
|
||||
"veloren-voxygen-i18n",
|
||||
"veloren-world",
|
||||
@ -7111,6 +7114,16 @@ dependencies = [
|
||||
"veloren-common-dynlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "veloren-voxygen-chat-i18n"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"veloren-common",
|
||||
"veloren-common-net",
|
||||
"veloren-voxygen-i18n",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "veloren-voxygen-egui"
|
||||
version = "0.9.0"
|
||||
|
@ -20,6 +20,7 @@ members = [
|
||||
"server-cli",
|
||||
"voxygen",
|
||||
"voxygen/anim",
|
||||
"voxygen/chat-i18n",
|
||||
"voxygen/i18n",
|
||||
"voxygen/egui",
|
||||
"world",
|
||||
|
@ -7,7 +7,7 @@ edition = "2021"
|
||||
[features]
|
||||
simd = ["vek/platform_intrinsics"]
|
||||
plugins = ["common-state/plugins"]
|
||||
bin_bot = ["common-ecs", "serde", "ron", "clap", "structopt", "rustyline", "common-frontend", "async-channel"]
|
||||
bin_bot = ["common-ecs", "serde", "ron", "clap", "structopt", "rustyline", "common-frontend", "async-channel", "voxygen-chat-i18n", "voxygen-i18n"]
|
||||
tracy = ["common-base/tracy"]
|
||||
tick_network = []
|
||||
|
||||
@ -37,6 +37,8 @@ authc = { git = "https://gitlab.com/veloren/auth.git", rev = "fb3dcbc4962b367253
|
||||
#bot only
|
||||
async-channel = { version = "1.6", optional = true }
|
||||
common-ecs = { package = "veloren-common-ecs", path = "../common/ecs", optional = true }
|
||||
voxygen-chat-i18n = { package = "veloren-voxygen-chat-i18n", path = "../voxygen/chat-i18n", optional = true }
|
||||
voxygen-i18n = { package = "veloren-voxygen-i18n", path = "../voxygen/i18n", optional = true }
|
||||
serde = { version = "1.0", features = [ "rc", "derive" ], optional = true }
|
||||
ron = { version = "0.8", default-features = false, optional = true }
|
||||
clap = { version = "3.1.8", optional = true, features = ["color", "std"] }
|
||||
|
@ -11,6 +11,7 @@ use std::{
|
||||
use tokio::runtime::Runtime;
|
||||
use tracing::{error, info};
|
||||
use veloren_client::{addr::ConnectionArgs, Client, Event};
|
||||
use voxygen_chat_i18n::internationalisate_chat_message;
|
||||
|
||||
const TPS: u64 = 10; // Low value is okay, just reading messages.
|
||||
|
||||
@ -28,6 +29,10 @@ fn main() {
|
||||
// Initialize logging.
|
||||
common_frontend::init_stdout(None);
|
||||
|
||||
info!("locading localisation");
|
||||
|
||||
let localisation = voxygen_i18n::LocalizationHandle::load_expect("en");
|
||||
|
||||
info!("Starting chat-cli...");
|
||||
|
||||
// Set up an fps clock.
|
||||
@ -63,7 +68,7 @@ fn main() {
|
||||
|
||||
println!("Server info: {:?}", client.server_info());
|
||||
|
||||
println!("Players online: {:?}", client.players().collect::<Vec<_>>());
|
||||
let mut player_printed = false;
|
||||
|
||||
let (tx, rx) = mpsc::channel();
|
||||
thread::spawn(move || {
|
||||
@ -89,7 +94,16 @@ fn main() {
|
||||
const SHOW_NAME: bool = false;
|
||||
for event in events {
|
||||
match event {
|
||||
Event::Chat(m) => println!("{}", client.format_message(&m, SHOW_NAME)),
|
||||
Event::Chat(m) => println!(
|
||||
"{}",
|
||||
internationalisate_chat_message(
|
||||
m,
|
||||
|msg| client.lockup_msg_context(msg),
|
||||
&localisation.read(),
|
||||
SHOW_NAME,
|
||||
)
|
||||
.message
|
||||
),
|
||||
Event::Disconnect => {}, // TODO
|
||||
Event::DisconnectionNotification(time) => {
|
||||
let message = match time {
|
||||
@ -108,5 +122,10 @@ fn main() {
|
||||
|
||||
// Wait for the next tick.
|
||||
clock.tick();
|
||||
|
||||
if !player_printed {
|
||||
println!("Players online: {:?}", client.players().collect::<Vec<_>>());
|
||||
player_printed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2643,8 +2643,13 @@ impl Client {
|
||||
|
||||
/// Get important information from client that is necessary for message
|
||||
/// localisation
|
||||
pub fn lockup_msg_context(&self, msg: &comp::ChatMsg) -> HashMap<&str, ChatTypeContext> {
|
||||
let mut result = HashMap::new();
|
||||
///
|
||||
/// Note: it uses the suffix `name` e.g. in `attacker_name` if Context is Raw, otherwise it returns just `attacker`
|
||||
pub fn lockup_msg_context(
|
||||
&self,
|
||||
msg: &comp::ChatMsg,
|
||||
) -> std::collections::HashMap<&'static str, ChatTypeContext> {
|
||||
let mut result = std::collections::HashMap::new();
|
||||
let comp::ChatMsg { chat_type, .. } = &msg;
|
||||
let name_of_uid = |uid| {
|
||||
let ecs = self.state.ecs();
|
||||
|
@ -50,6 +50,7 @@ common-state = {package = "veloren-common-state", path = "../common/state"}
|
||||
|
||||
anim = {package = "veloren-voxygen-anim", path = "anim"}
|
||||
i18n = {package = "veloren-voxygen-i18n", path = "i18n"}
|
||||
chat-i18n = {package = "veloren-voxygen-chat-i18n", path = "chat-i18n"}
|
||||
voxygen-egui = {package = "veloren-voxygen-egui", path = "egui", optional = true }
|
||||
|
||||
# Graphics
|
||||
|
13
voxygen/chat-i18n/Cargo.toml
Normal file
13
voxygen/chat-i18n/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
authors = ["juliancoffee <lightdarkdaughter@gmail.com>"]
|
||||
edition = "2021"
|
||||
name = "veloren-voxygen-chat-i18n"
|
||||
description = "Crate for internalization and diagnostic of existing localizations."
|
||||
version = "0.10.0"
|
||||
|
||||
[dependencies]
|
||||
common-net = {package = "veloren-common-net", path = "../../common/net"}
|
||||
common = {package = "veloren-common", path = "../../common"}
|
||||
i18n = {package = "veloren-voxygen-i18n", path = "../i18n"}
|
||||
# Utility
|
||||
tracing = "0.1"
|
136
voxygen/chat-i18n/src/lib.rs
Normal file
136
voxygen/chat-i18n/src/lib.rs
Normal file
@ -0,0 +1,136 @@
|
||||
use common::comp::{
|
||||
chat::{KillSource, KillType},
|
||||
BuffKind, ChatMsg, ChatType,
|
||||
};
|
||||
use common_net::msg::{ChatTypeContext, PlayerInfo};
|
||||
use i18n::Localization;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn internationalisate_chat_message(
|
||||
mut msg: ChatMsg,
|
||||
lookup_fn: impl Fn(&ChatMsg) -> HashMap<&'static str, ChatTypeContext>,
|
||||
localized_strings: &Localization,
|
||||
show_char_name: bool,
|
||||
) -> ChatMsg {
|
||||
if let Some(template_key) = get_chat_template_key(&msg.chat_type) {
|
||||
msg.message = localized_strings
|
||||
.get_msg_ctx(template_key, &i18n::fluent_args! {
|
||||
"attacker" => "{attacker}",
|
||||
"attacker" => "{attacker_name}",
|
||||
"name" => "{player}",
|
||||
"died_of_buff" => "{died_of_buff}",
|
||||
"victim" => "{victim}",
|
||||
"environment" => "{environment}",
|
||||
})
|
||||
.into_owned();
|
||||
|
||||
if let ChatType::Kill(kill_source, _) = &msg.chat_type {
|
||||
match kill_source {
|
||||
KillSource::Player(_, KillType::Buff(buffkind))
|
||||
| KillSource::NonExistent(KillType::Buff(buffkind))
|
||||
| KillSource::NonPlayer(_, KillType::Buff(buffkind)) => {
|
||||
msg.message = insert_killing_buff(*buffkind, localized_strings, &msg.message);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
let info = lookup_fn(&msg);
|
||||
let gen_alias = |you, info: PlayerInfo| {
|
||||
let mod_str = if info.is_moderator { "MOD - " } else { "" };
|
||||
let you_str = if you { "You" } else { &info.player_alias };
|
||||
format!("{}{}", mod_str, you_str)
|
||||
};
|
||||
let message_format = |you, info: PlayerInfo, message: &str, group: Option<&String>| {
|
||||
let alias = gen_alias(you, info.clone());
|
||||
let name = if show_char_name {
|
||||
info.character.map(|c| c.name)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
match (group, name) {
|
||||
(Some(group), None) => format!("({}) [{}]: {}", group, alias, message),
|
||||
(None, None) => format!("[{}]: {}", alias, message),
|
||||
(Some(group), Some(name)) => {
|
||||
format!("({}) [{}] {}: {}", group, alias, name, message)
|
||||
},
|
||||
(None, Some(name)) => format!("[{}] {}: {}", alias, name, message),
|
||||
}
|
||||
};
|
||||
if let Some(ChatTypeContext::PlayerAlias { you, info }) = info.get("from").cloned() {
|
||||
msg.message = match &msg.chat_type {
|
||||
ChatType::Say(_) => message_format(you, info, &msg.message, None),
|
||||
ChatType::Group(_, s) => message_format(you, info, &msg.message, Some(s)),
|
||||
ChatType::Faction(_, s) => message_format(you, info, &msg.message, Some(s)),
|
||||
ChatType::Region(_) => message_format(you, info, &msg.message, None),
|
||||
ChatType::World(_) => message_format(you, info, &msg.message, None),
|
||||
ChatType::NpcSay(_, _r) => message_format(you, info, &msg.message, None),
|
||||
_ => msg.message,
|
||||
};
|
||||
}
|
||||
for (name, datum) in info.into_iter() {
|
||||
let replacement = match datum {
|
||||
ChatTypeContext::PlayerAlias { you, info } => gen_alias(you, info),
|
||||
ChatTypeContext::Raw(text) => text,
|
||||
};
|
||||
msg.message = msg.message.replace(&format!("{{{}}}", name), &replacement);
|
||||
}
|
||||
msg
|
||||
}
|
||||
|
||||
fn get_chat_template_key(chat_type: &ChatType<String>) -> Option<&str> {
|
||||
Some(match chat_type {
|
||||
ChatType::Online(_) => "hud-chat-online_msg",
|
||||
ChatType::Offline(_) => "hud-chat-offline_msg",
|
||||
ChatType::Kill(kill_source, _) => match kill_source {
|
||||
KillSource::Player(_, KillType::Buff(_)) => "hud-chat-died_of_pvp_buff_msg",
|
||||
KillSource::Player(_, KillType::Melee) => "hud-chat-pvp_melee_kill_msg",
|
||||
KillSource::Player(_, KillType::Projectile) => "hud-chat-pvp_ranged_kill_msg",
|
||||
KillSource::Player(_, KillType::Explosion) => "hud-chat-pvp_explosion_kill_msg",
|
||||
KillSource::Player(_, KillType::Energy) => "hud-chat-pvp_energy_kill_msg",
|
||||
KillSource::Player(_, KillType::Other) => "hud-chat-pvp_other_kill_msg",
|
||||
KillSource::NonExistent(KillType::Buff(_)) => "hud-chat-died_of_buff_nonexistent_msg",
|
||||
KillSource::NonPlayer(_, KillType::Buff(_)) => "hud-chat-died_of_npc_buff_msg",
|
||||
KillSource::NonPlayer(_, KillType::Melee) => "hud-chat-npc_melee_kill_msg",
|
||||
KillSource::NonPlayer(_, KillType::Projectile) => "hud-chat-npc_ranged_kill_msg",
|
||||
KillSource::NonPlayer(_, KillType::Explosion) => "hud-chat-npc_explosion_kill_msg",
|
||||
KillSource::NonPlayer(_, KillType::Energy) => "hud-chat-npc_energy_kill_msg",
|
||||
KillSource::NonPlayer(_, KillType::Other) => "hud-chat-npc_other_kill_msg",
|
||||
KillSource::Environment(_) => "hud-chat-environmental_kill_msg",
|
||||
KillSource::FallDamage => "hud-chat-fall_kill_msg",
|
||||
KillSource::Suicide => "hud-chat-suicide_msg",
|
||||
KillSource::NonExistent(_) | KillSource::Other => "hud-chat-default_death_msg",
|
||||
},
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
fn insert_killing_buff(buff: BuffKind, localized_strings: &Localization, template: &str) -> String {
|
||||
let buff_outcome = match buff {
|
||||
BuffKind::Burning => "hud-outcome-burning",
|
||||
BuffKind::Bleeding => "hud-outcome-bleeding",
|
||||
BuffKind::Cursed => "hud-outcome-curse",
|
||||
BuffKind::Crippled => "hud-outcome-crippled",
|
||||
BuffKind::Frozen => "hud-outcome-frozen",
|
||||
BuffKind::Regeneration
|
||||
| BuffKind::Saturation
|
||||
| BuffKind::Potion
|
||||
| BuffKind::CampfireHeal
|
||||
| BuffKind::EnergyRegen
|
||||
| BuffKind::IncreaseMaxEnergy
|
||||
| BuffKind::IncreaseMaxHealth
|
||||
| BuffKind::Invulnerability
|
||||
| BuffKind::ProtectingWard
|
||||
| BuffKind::Frenzied
|
||||
| BuffKind::Hastened => {
|
||||
tracing::error!("Player was killed by a positive buff!");
|
||||
"hud-outcome-mysterious"
|
||||
},
|
||||
BuffKind::Wet | BuffKind::Ensnared | BuffKind::Poisoned => {
|
||||
tracing::error!("Player was killed by a debuff that doesn't do damage!");
|
||||
"hud-outcome-mysterious"
|
||||
},
|
||||
};
|
||||
|
||||
template.replace("{died_of_buff}", &localized_strings.get_msg(buff_outcome))
|
||||
}
|
@ -3,13 +3,9 @@ use super::{
|
||||
OFFLINE_COLOR, ONLINE_COLOR, REGION_COLOR, SAY_COLOR, TELL_COLOR, TEXT_COLOR, WORLD_COLOR,
|
||||
};
|
||||
use crate::{cmd::complete, settings::chat::MAX_CHAT_TABS, ui::fonts::Fonts, GlobalState};
|
||||
use chat_i18n::internationalisate_chat_message;
|
||||
use client::Client;
|
||||
use common::comp::{
|
||||
chat::{KillSource, KillType},
|
||||
group::Role,
|
||||
BuffKind, ChatMode, ChatMsg, ChatType,
|
||||
};
|
||||
use common_net::msg::{ChatTypeContext, PlayerInfo};
|
||||
use common::comp::{group::Role, ChatMode, ChatMsg, ChatType};
|
||||
use conrod_core::{
|
||||
color,
|
||||
input::Key,
|
||||
@ -425,8 +421,8 @@ impl<'a> Widget for Chat<'a> {
|
||||
.map(|m| {
|
||||
internationalisate_chat_message(
|
||||
m.clone(),
|
||||
&self.client,
|
||||
&self.localized_strings,
|
||||
|msg| self.client.lockup_msg_context(msg),
|
||||
self.localized_strings,
|
||||
show_char_name,
|
||||
)
|
||||
})
|
||||
@ -662,80 +658,6 @@ impl<'a> Widget for Chat<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn internationalisate_chat_message(
|
||||
mut msg: ChatMsg,
|
||||
client: &Client,
|
||||
localized_strings: &Localization,
|
||||
show_char_name: bool,
|
||||
) -> ChatMsg {
|
||||
if let Some(template_key) = get_chat_template_key(&msg.chat_type) {
|
||||
// FIXME (i18n death messages):
|
||||
// Death message is half localized in voxygen, half in client.
|
||||
// Make this not.
|
||||
msg.message = localized_strings
|
||||
.get_msg_ctx(template_key, &i18n::fluent_args! {
|
||||
"attacker" => "{attacker}",
|
||||
"name" => "{name}",
|
||||
"died_of_buff" => "{died_of_buff}",
|
||||
"victim" => "{victim}",
|
||||
"environment" => "{environment}",
|
||||
})
|
||||
.into_owned();
|
||||
|
||||
if let ChatType::Kill(kill_source, _) = &msg.chat_type {
|
||||
match kill_source {
|
||||
KillSource::Player(_, KillType::Buff(buffkind))
|
||||
| KillSource::NonExistent(KillType::Buff(buffkind))
|
||||
| KillSource::NonPlayer(_, KillType::Buff(buffkind)) => {
|
||||
msg.message = insert_killing_buff(*buffkind, localized_strings, &msg.message);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
let info = client.lockup_msg_context(&msg);
|
||||
let gen_alias = |you, info: PlayerInfo| {
|
||||
let mod_str = if info.is_moderator { "MOD - " } else { "" };
|
||||
let you_str = if you { "You" } else { &info.player_alias };
|
||||
format!("{}{}", mod_str, you_str)
|
||||
};
|
||||
let message_format = |you, info: PlayerInfo, message: &str, group: Option<&String>| {
|
||||
let alias = gen_alias(you, info.clone());
|
||||
let name = if show_char_name {
|
||||
info.character.map(|c| c.name)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
match (group, name) {
|
||||
(Some(group), None) => format!("({}) [{}]: {}", group, alias, message),
|
||||
(None, None) => format!("[{}]: {}", alias, message),
|
||||
(Some(group), Some(name)) => {
|
||||
format!("({}) [{}] {}: {}", group, alias, name, message)
|
||||
},
|
||||
(None, Some(name)) => format!("[{}] {}: {}", alias, name, message),
|
||||
}
|
||||
};
|
||||
if let Some(ChatTypeContext::PlayerAlias { you, info }) = info.get("from").cloned() {
|
||||
msg.message = match &msg.chat_type {
|
||||
ChatType::Say(_) => message_format(you, info, &msg.message, None),
|
||||
ChatType::Group(_, s) => message_format(you, info, &msg.message, Some(s)),
|
||||
ChatType::Faction(_, s) => message_format(you, info, &msg.message, Some(s)),
|
||||
ChatType::Region(_) => message_format(you, info, &msg.message, None),
|
||||
ChatType::World(_) => message_format(you, info, &msg.message, None),
|
||||
ChatType::NpcSay(_, _r) => message_format(you, info, &msg.message, None),
|
||||
_ => msg.message,
|
||||
};
|
||||
}
|
||||
for (name, datum) in info.into_iter() {
|
||||
let replacement = match datum {
|
||||
ChatTypeContext::PlayerAlias { you, info } => gen_alias(you, info),
|
||||
ChatTypeContext::Raw(text) => text,
|
||||
};
|
||||
msg.message = msg.message.replace(&format!("{{{}}}", name), &replacement);
|
||||
}
|
||||
msg
|
||||
}
|
||||
|
||||
fn do_tab_completion(cursor: usize, input: &str, word: &str) -> (String, usize) {
|
||||
let mut pre_ws = None;
|
||||
let mut post_ws = None;
|
||||
@ -825,63 +747,6 @@ fn render_chat_line(chat_type: &ChatType<String>, imgs: &Imgs) -> (Color, conrod
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_killing_buff(buff: BuffKind, localized_strings: &Localization, template: &str) -> String {
|
||||
let buff_outcome = match buff {
|
||||
BuffKind::Burning => "hud-outcome-burning",
|
||||
BuffKind::Bleeding => "hud-outcome-bleeding",
|
||||
BuffKind::Cursed => "hud-outcome-curse",
|
||||
BuffKind::Crippled => "hud-outcome-crippled",
|
||||
BuffKind::Frozen => "hud-outcome-frozen",
|
||||
BuffKind::Regeneration
|
||||
| BuffKind::Saturation
|
||||
| BuffKind::Potion
|
||||
| BuffKind::CampfireHeal
|
||||
| BuffKind::EnergyRegen
|
||||
| BuffKind::IncreaseMaxEnergy
|
||||
| BuffKind::IncreaseMaxHealth
|
||||
| BuffKind::Invulnerability
|
||||
| BuffKind::ProtectingWard
|
||||
| BuffKind::Frenzied
|
||||
| BuffKind::Hastened => {
|
||||
tracing::error!("Player was killed by a positive buff!");
|
||||
"hud-outcome-mysterious"
|
||||
},
|
||||
BuffKind::Wet | BuffKind::Ensnared | BuffKind::Poisoned => {
|
||||
tracing::error!("Player was killed by a debuff that doesn't do damage!");
|
||||
"hud-outcome-mysterious"
|
||||
},
|
||||
};
|
||||
|
||||
template.replace("{died_of_buff}", &localized_strings.get_msg(buff_outcome))
|
||||
}
|
||||
|
||||
fn get_chat_template_key(chat_type: &ChatType<String>) -> Option<&str> {
|
||||
Some(match chat_type {
|
||||
ChatType::Online(_) => "hud-chat-online_msg",
|
||||
ChatType::Offline(_) => "hud-chat-offline_msg",
|
||||
ChatType::Kill(kill_source, _) => match kill_source {
|
||||
KillSource::Player(_, KillType::Buff(_)) => "hud-chat-died_of_pvp_buff_msg",
|
||||
KillSource::Player(_, KillType::Melee) => "hud-chat-pvp_melee_kill_msg",
|
||||
KillSource::Player(_, KillType::Projectile) => "hud-chat-pvp_ranged_kill_msg",
|
||||
KillSource::Player(_, KillType::Explosion) => "hud-chat-pvp_explosion_kill_msg",
|
||||
KillSource::Player(_, KillType::Energy) => "hud-chat-pvp_energy_kill_msg",
|
||||
KillSource::Player(_, KillType::Other) => "hud-chat-pvp_other_kill_msg",
|
||||
KillSource::NonExistent(KillType::Buff(_)) => "hud-chat-died_of_buff_nonexistent_msg",
|
||||
KillSource::NonPlayer(_, KillType::Buff(_)) => "hud-chat-died_of_npc_buff_msg",
|
||||
KillSource::NonPlayer(_, KillType::Melee) => "hud-chat-npc_melee_kill_msg",
|
||||
KillSource::NonPlayer(_, KillType::Projectile) => "hud-chat-npc_ranged_kill_msg",
|
||||
KillSource::NonPlayer(_, KillType::Explosion) => "hud-chat-npc_explosion_kill_msg",
|
||||
KillSource::NonPlayer(_, KillType::Energy) => "hud-chat-npc_energy_kill_msg",
|
||||
KillSource::NonPlayer(_, KillType::Other) => "hud-chat-npc_other_kill_msg",
|
||||
KillSource::Environment(_) => "hud-chat-environmental_kill_msg",
|
||||
KillSource::FallDamage => "hud-chat-fall_kill_msg",
|
||||
KillSource::Suicide => "hud-chat-suicide_msg",
|
||||
KillSource::NonExistent(_) | KillSource::Other => "hud-chat-default_death_msg",
|
||||
},
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_cmd(msg: &str) -> Result<(String, Vec<String>), String> {
|
||||
use chumsky::prelude::*;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user