Localize command descriptions & help summaries

This commit is contained in:
coffee-compiler 2024-08-17 18:12:55 +00:00 committed by Illia Denysenko
parent 68b74000f7
commit 9e55aaa702
8 changed files with 355 additions and 237 deletions

View File

@ -23,7 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Craftable orichalcum helmet
- Protocol to query game server information (player count, version, etc.) and make ping tests.
- Unlockable recipes
- Localization support for prompt dialogs, diary sections, trade and group invitations.
- Localization support for prompt dialogs, diary sections, trade and group invitations, command descriptions.
- Added Freezing Potion
- Clear command to delete chat messages.

1
Cargo.lock generated
View File

@ -7503,6 +7503,7 @@ dependencies = [
"veloren-common-base",
"veloren-common-ecs",
"veloren-common-frontend",
"veloren-common-i18n",
"veloren-common-net",
"veloren-common-state",
"veloren-common-systems",

View File

@ -1,3 +1,116 @@
# Descriptions and Help
command-help-template = { $usage } { $description }
command-help-additional-shortcuts = Additionally, you can use the following shortcuts:
## Server Commands
command-adminify-desc = Temporarily gives a player a restricted admin role or removes the current one (if not given)
command-airship-desc = Spawns an airship
command-alias-desc = Change your alias
command-area_add-desc = Adds a new build area
command-area_list-desc = List all build areas
command-area_remove-desc = Removes specified build area
command-aura-desc = Create an aura
command-body-desc = Change your body to different species
command-buff-desc = Cast a buff on player
command-build-desc = Toggles build mode on and off
command-ban-desc = Ban a player with a given username, for a given duration (if provided). Pass true for overwrite to alter an existing ban.
command-battlemode-desc = Set your battle mode to:
+ pvp (player vs player)
+ pve (player vs environment).
If called without arguments will show current battle mode.
command-battlemode_force-desc = Change your battle mode flag without any checks
command-campfire-desc = Spawns a campfire
command-clear_persisted_terrain-desc = Clears nearby persisted terrain
command-create_location-desc = Create a location at the current position
command-debug_column-desc = Prints some debug information about a column
command-debug_ways-desc = Prints some debug information about a column's ways
command-delete_location-desc = Delete a location
command-destroy_tethers-desc = Destroy all tethers connected to you
command-disconnect_all_players-desc = Disconnects all players from the server
command-dismount-desc = Dismount if you are riding, or dismount anything riding you
command-dropall-desc = Drops all your items on the ground
command-dummy-desc = Spawns a training dummy
command-explosion-desc = Explodes the ground around you
command-faction-desc = Send messages to your faction
command-give_item-desc = Give yourself some items. For an example or to auto complete use Tab.
command-goto-desc = Teleport to a position
command-group-desc = Send messages to your group
command-group_invite-desc = Invite a player to join a group
command-group_kick-desc = Remove a player from a group
command-group_leave-desc = Leave the current group
command-group_promote-desc = Promote a player to group leader
command-health-desc = Set your current health
command-into_npc-desc = Convert yourself to an NPC. Be careful!
command-join_faction-desc = Join/leave the specified faction
command-jump-desc = Offset your current position
command-kick-desc = Kick a player with a given username
command-kill-desc = Kill yourself
command-kill_npcs-desc = Kill the NPCs
command-kit-desc = Place a set of items into your inventory.
command-lantern-desc = Change your lantern's strength and color
command-light-desc = Spawn entity with light
command-lightning-desc = Lightning strike at current position
command-location-desc = Teleport to a location
command-make_block-desc = Make a block at your location with a color
command-make_npc-desc = Spawn entity from config near you.
For an example or to auto complete use Tab.
command-make_sprite-desc = Make a sprite at your location
command-make_volume-desc = Create a volume (experimental)
command-motd-desc = View the server description
command-mount-desc = Mount an entity
command-object-desc = Spawn an object
command-permit_build-desc = Grants player a bounded box they can build in
command-players-desc = Lists players currently online
command-portal-desc = Spawns a portal
command-region-desc = Send messages to everyone in your region of the world
command-reload_chunks-desc = Reloads chunks loaded on the server
command-remove_lights-desc = Removes all lights spawned by players
command-repair_equipment-desc = Repairs all equipped items
command-reset_recipes-desc = Resets your recipe book
command-respawn-desc = Teleport to your waypoint
command-revoke_build-desc = Revokes build area permission for player
command-revoke_build_all-desc = Revokes all build area permissions for player
command-safezone-desc = Creates a safezone
command-say-desc = Send messages to everyone within shouting distance
command-scale-desc = Scale your character
command-server_physics-desc = Set/unset server-authoritative physics for an account
command-set_motd-desc = Set the server description
command-ship-desc = Spawns a ship
command-site-desc = Teleport to a site
command-skill_point-desc = Give yourself skill points for a particular skill tree
command-skill_preset-desc = Gives your character desired skills.
command-spawn-desc = Spawn a test entity
command-sudo-desc = Run command as if you were another entity
command-tell-desc = Send a message to another player
command-tether-desc = Tether another entity to yourself
command-time-desc = Set the time of day
command-time_scale-desc = Set scaling of delta time
command-tp-desc = Teleport to another entity
command-rtsim_chunk-desc = Display information about the current chunk from rtsim
command-rtsim_info-desc = Display information about an rtsim NPC
command-rtsim_npc-desc = List rtsim NPCs that fit a given query (e.g: simulated,merchant) in order of distance
command-rtsim_purge-desc = Purge rtsim data on next startup
command-rtsim_tp-desc = Teleport to an rtsim npc
command-unban-desc = Remove the ban for the given username
command-version-desc = Prints server version
command-waypoint-desc = Set your waypoint to your current position
command-weather_zone-desc = Create a weather zone
command-whitelist-desc = Adds/removes username to whitelist
command-wiring-desc = Create wiring element
command-world-desc = Send messages to everyone on the server
## Voxygen Client Commands
command-clear-desc = Clears all messages in chat. Affects all chat tabs.
command-experimental_shader-desc = Toggles an experimental shader.
command-help-desc = Display information about commands
command-mute-desc = Mutes chat messages from a player.
command-unmute-desc = Unmutes a player muted with the 'mute' command.
# Results and Warning
command-no-permission = You don't have permission to use '/{ $command_name }'
command-position-unavailable = Cannot get position for { $target }
command-player-role-unavailable = Cannot get administrator roles for { $target }

View File

@ -10,6 +10,7 @@ use crate::{
recipe::RecipeBookManifest,
terrain,
};
use common_i18n::Content;
use hashbrown::HashMap;
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
@ -24,18 +25,14 @@ use tracing::warn;
pub struct ChatCommandData {
/// A list of arguments useful for both tab completion and parsing
pub args: Vec<ArgumentSpec>,
/// A one-line message that explains what the command does
pub description: &'static str,
/// The i18n content for the description of the command
pub description: Content,
/// Whether the command requires administrator permissions.
pub needs_role: Option<Role>,
}
impl ChatCommandData {
pub fn new(
args: Vec<ArgumentSpec>,
description: &'static str,
needs_role: Option<Role>,
) -> Self {
pub fn new(args: Vec<ArgumentSpec>, description: Content, needs_role: Option<Role>) -> Self {
Self {
args,
description,
@ -358,7 +355,6 @@ pub enum ServerChatCommand {
GroupLeave,
GroupPromote,
Health,
Help,
IntoNpc,
JoinFaction,
Jump,
@ -427,8 +423,7 @@ impl ServerChatCommand {
match self {
ServerChatCommand::Adminify => cmd(
vec![PlayerName(Required), Enum("role", ROLES.clone(), Optional)],
"Temporarily gives a player a restricted admin role or removes the current one \
(if not given)",
Content::localized("command-adminify-desc"),
Some(Admin),
),
ServerChatCommand::Airship => cmd(
@ -443,12 +438,12 @@ impl ServerChatCommand {
),
Float("destination_degrees_ccw_of_east", 90.0, Optional),
],
"Spawns an airship",
Content::localized("command-airship-desc"),
Some(Admin),
),
ServerChatCommand::Alias => cmd(
vec![Any("name", Required)],
"Change your alias",
Content::localized("command-alias-desc"),
Some(Moderator),
),
ServerChatCommand::Aura => cmd(
@ -460,7 +455,7 @@ impl ServerChatCommand {
Enum("aura_kind", AuraKindVariant::all_options(), Required),
Any("aura spec", Optional),
],
"Create an aura",
Content::localized("command-aura-desc"),
Some(Admin),
),
ServerChatCommand::Buff => cmd(
@ -470,7 +465,7 @@ impl ServerChatCommand {
Float("duration", 10.0, Optional),
Any("buff data spec", Optional),
],
"Cast a buff on player",
Content::localized("command-buff-desc"),
Some(Admin),
),
ServerChatCommand::Ban => cmd(
@ -480,8 +475,7 @@ impl ServerChatCommand {
Any("ban duration", Optional),
Message(Optional),
],
"Ban a player with a given username, for a given duration (if provided). Pass \
true for overwrite to alter an existing ban..",
Content::localized("command-ban-desc"),
Some(Moderator),
),
#[rustfmt::skip]
@ -491,10 +485,7 @@ impl ServerChatCommand {
vec!["pvp".to_owned(), "pve".to_owned()],
Optional,
)],
"Set your battle mode to:\n\
* pvp (player vs player)\n\
* pve (player vs environment).\n\
If called without arguments will show current battle mode.",
Content::localized("command-battlemode-desc"),
None,
),
@ -505,12 +496,12 @@ impl ServerChatCommand {
ENTITY_CONFIGS.clone(),
Required,
)],
"Convert yourself to an NPC. Be careful!",
Content::localized("command-into_npc-desc"),
Some(Admin),
),
ServerChatCommand::Body => cmd(
vec![Enum("body", ENTITIES.clone(), Required)],
"Change your body to different species",
Content::localized("command-body-desc"),
Some(Admin),
),
ServerChatCommand::BattleModeForce => cmd(
@ -519,10 +510,10 @@ impl ServerChatCommand {
vec!["pvp".to_owned(), "pve".to_owned()],
Required,
)],
"Change your battle mode flag without any checks",
Content::localized("command-battlemode_force-desc"),
Some(Admin),
),
ServerChatCommand::Build => cmd(vec![], "Toggles build mode on and off", None),
ServerChatCommand::Build => cmd(vec![], Content::localized("command-build-desc"), None),
ServerChatCommand::AreaAdd => cmd(
vec![
Any("name", Required),
@ -534,53 +525,65 @@ impl ServerChatCommand {
Integer("zlo", 0, Required),
Integer("zhi", 10, Required),
],
"Adds a new build area",
Content::localized("command-area_add-desc"),
Some(Admin),
),
ServerChatCommand::AreaList => cmd(
vec![],
Content::localized("command-area_list-desc"),
Some(Admin),
),
ServerChatCommand::AreaList => cmd(vec![], "List all build areas", Some(Admin)),
ServerChatCommand::AreaRemove => cmd(
vec![
Any("name", Required),
Enum("kind", AREA_KINDS.clone(), Required),
],
"Removes specified build area",
Content::localized("command-area_remove-desc"),
Some(Admin),
),
ServerChatCommand::Campfire => cmd(
vec![],
Content::localized("command-campfire-desc"),
Some(Admin),
),
ServerChatCommand::Campfire => cmd(vec![], "Spawns a campfire", Some(Admin)),
ServerChatCommand::ClearPersistedTerrain => cmd(
vec![Integer("chunk_radius", 6, Required)],
"Clears nearby persisted terrain",
Content::localized("command-clear_persisted_terrain-desc"),
Some(Admin),
),
ServerChatCommand::DebugColumn => cmd(
vec![Integer("x", 15000, Required), Integer("y", 15000, Required)],
"Prints some debug information about a column",
Content::localized("command-debug_column-desc"),
Some(Admin),
),
ServerChatCommand::DebugWays => cmd(
vec![Integer("x", 15000, Required), Integer("y", 15000, Required)],
"Prints some debug information about a column's ways",
Content::localized("command-debug_ways-desc"),
Some(Admin),
),
ServerChatCommand::DisconnectAllPlayers => cmd(
vec![Any("confirm", Required)],
"Disconnects all players from the server",
Content::localized("command-disconnect_all_players-desc"),
Some(Admin),
),
ServerChatCommand::DropAll => cmd(
vec![],
"Drops all your items on the ground",
Content::localized("command-dropall-desc"),
Some(Moderator),
),
ServerChatCommand::Dummy => cmd(vec![], "Spawns a training dummy", Some(Admin)),
ServerChatCommand::Dummy => cmd(
vec![],
Content::localized("command-dummy-desc"),
Some(Admin),
),
ServerChatCommand::Explosion => cmd(
vec![Float("radius", 5.0, Required)],
"Explodes the ground around you",
Content::localized("command-explosion-desc"),
Some(Admin),
),
ServerChatCommand::Faction => cmd(
vec![Message(Optional)],
"Send messages to your faction",
Content::localized("command-faction-desc"),
None,
),
ServerChatCommand::GiveItem => cmd(
@ -588,7 +591,7 @@ impl ServerChatCommand {
AssetPath("item", "common.items.", ITEM_SPECS.clone(), Required),
Integer("num", 1, Optional),
],
"Give yourself some items.\nFor an example or to auto complete use Tab.",
Content::localized("command-give_item-desc"),
Some(Admin),
),
ServerChatCommand::Goto => cmd(
@ -598,42 +601,45 @@ impl ServerChatCommand {
Float("z", 0.0, Required),
Boolean("Dismount from ship", "true".to_string(), Optional),
],
"Teleport to a position",
Content::localized("command-goto-desc"),
Some(Admin),
),
ServerChatCommand::Group => {
cmd(vec![Message(Optional)], "Send messages to your group", None)
},
ServerChatCommand::Group => cmd(
vec![Message(Optional)],
Content::localized("command-group-desc"),
None,
),
ServerChatCommand::GroupInvite => cmd(
vec![PlayerName(Required)],
"Invite a player to join a group",
Content::localized("command-group_invite-desc"),
None,
),
ServerChatCommand::GroupKick => cmd(
vec![PlayerName(Required)],
"Remove a player from a group",
Content::localized("command-group_kick-desc"),
None,
),
ServerChatCommand::GroupLeave => cmd(vec![], "Leave the current group", None),
ServerChatCommand::GroupLeave => {
cmd(vec![], Content::localized("command-group_leave-desc"), None)
},
ServerChatCommand::GroupPromote => cmd(
vec![PlayerName(Required)],
"Promote a player to group leader",
Content::localized("command-group_promote-desc"),
None,
),
ServerChatCommand::Health => cmd(
vec![Integer("hp", 100, Required)],
"Set your current health",
Content::localized("command-health-desc"),
Some(Admin),
),
ServerChatCommand::Help => ChatCommandData::new(
vec![Command(Optional)],
"Display information about commands",
None,
ServerChatCommand::Respawn => cmd(
vec![],
Content::localized("command-respawn-desc"),
Some(Moderator),
),
ServerChatCommand::Respawn => cmd(vec![], "Teleport to your waypoint", Some(Moderator)),
ServerChatCommand::JoinFaction => ChatCommandData::new(
ServerChatCommand::JoinFaction => cmd(
vec![Any("faction", Optional)],
"Join/leave the specified faction",
Content::localized("command-join_faction-desc"),
None,
),
ServerChatCommand::Jump => cmd(
@ -643,23 +649,23 @@ impl ServerChatCommand {
Float("z", 0.0, Required),
Boolean("Dismount from ship", "true".to_string(), Optional),
],
"Offset your current position",
Content::localized("command-jump-desc"),
Some(Admin),
),
ServerChatCommand::Kick => cmd(
vec![PlayerName(Required), Message(Optional)],
"Kick a player with a given username",
Content::localized("command-kick-desc"),
Some(Moderator),
),
ServerChatCommand::Kill => cmd(vec![], "Kill yourself", None),
ServerChatCommand::Kill => cmd(vec![], Content::localized("command-kill-desc"), None),
ServerChatCommand::KillNpcs => cmd(
vec![Float("radius", 100.0, Optional), Flag("--also-pets")],
"Kill the NPCs",
Content::localized("command-kill_npcs-desc"),
Some(Admin),
),
ServerChatCommand::Kit => cmd(
vec![Enum("kit_name", KITS.to_vec(), Required)],
"Place a set of items into your inventory.",
Content::localized("command-kit-desc"),
Some(Admin),
),
ServerChatCommand::Lantern => cmd(
@ -669,7 +675,7 @@ impl ServerChatCommand {
Float("g", 1.0, Optional),
Float("b", 1.0, Optional),
],
"Change your lantern's strength and color",
Content::localized("command-lantern-desc"),
Some(Admin),
),
ServerChatCommand::Light => cmd(
@ -682,7 +688,7 @@ impl ServerChatCommand {
Float("z", 0.0, Optional),
Float("strength", 5.0, Optional),
],
"Spawn entity with light",
Content::localized("command-light-desc"),
Some(Admin),
),
ServerChatCommand::MakeBlock => cmd(
@ -692,7 +698,7 @@ impl ServerChatCommand {
Integer("g", 255, Optional),
Integer("b", 255, Optional),
],
"Make a block at your location with a color",
Content::localized("command-make_block-desc"),
Some(Admin),
),
ServerChatCommand::MakeNpc => cmd(
@ -705,26 +711,28 @@ impl ServerChatCommand {
),
Integer("num", 1, Optional),
],
"Spawn entity from config near you.\nFor an example or to auto complete use Tab.",
Content::localized("command-make_npc-desc"),
Some(Admin),
),
ServerChatCommand::MakeSprite => cmd(
vec![Enum("sprite", SPRITE_KINDS.clone(), Required)],
"Make a sprite at your location",
Content::localized("command-make_sprite-desc"),
Some(Admin),
),
ServerChatCommand::Motd => cmd(vec![], "View the server description", None),
ServerChatCommand::Motd => cmd(vec![], Content::localized("command-motd-desc"), None),
ServerChatCommand::Object => cmd(
vec![Enum("object", OBJECTS.clone(), Required)],
"Spawn an object",
Content::localized("command-object-desc"),
Some(Admin),
),
ServerChatCommand::PermitBuild => cmd(
vec![Any("area_name", Required)],
"Grants player a bounded box they can build in",
Content::localized("command-permit_build-desc"),
Some(Admin),
),
ServerChatCommand::Players => cmd(vec![], "Lists players currently online", None),
ServerChatCommand::Players => {
cmd(vec![], Content::localized("command-players-desc"), None)
},
ServerChatCommand::Portal => cmd(
vec![
Float("x", 0., Required),
@ -733,43 +741,47 @@ impl ServerChatCommand {
Boolean("requires_no_aggro", "true".to_string(), Optional),
Float("buildup_time", 5., Optional),
],
"Spawns a portal",
Content::localized("command-portal-desc"),
Some(Admin),
),
ServerChatCommand::ReloadChunks => cmd(
vec![Integer("chunk_radius", 6, Optional)],
"Reloads chunks loaded on the server",
Content::localized("command-reload_chunks-desc"),
Some(Admin),
),
ServerChatCommand::ResetRecipes => cmd(
vec![],
Content::localized("command-reset_recipes-desc"),
Some(Admin),
),
ServerChatCommand::ResetRecipes => cmd(vec![], "Resets your recipe book", Some(Admin)),
ServerChatCommand::RemoveLights => cmd(
vec![Float("radius", 20.0, Optional)],
"Removes all lights spawned by players",
Content::localized("command-remove_lights-desc"),
Some(Admin),
),
ServerChatCommand::RevokeBuild => cmd(
vec![Any("area_name", Required)],
"Revokes build area permission for player",
Content::localized("command-revoke_build-desc"),
Some(Admin),
),
ServerChatCommand::RevokeBuildAll => cmd(
vec![],
"Revokes all build area permissions for player",
Content::localized("command-revoke_build_all-desc"),
Some(Admin),
),
ServerChatCommand::Region => cmd(
vec![Message(Optional)],
"Send messages to everyone in your region of the world",
Content::localized("command-region-desc"),
None,
),
ServerChatCommand::Safezone => cmd(
vec![Float("range", 100.0, Optional)],
"Creates a safezone",
Content::localized("command-safezone-desc"),
Some(Moderator),
),
ServerChatCommand::Say => cmd(
vec![Message(Optional)],
"Send messages to everyone within shouting distance",
Content::localized("command-say-desc"),
None,
),
ServerChatCommand::ServerPhysics => cmd(
@ -777,12 +789,12 @@ impl ServerChatCommand {
PlayerName(Required),
Boolean("enabled", "true".to_string(), Optional),
],
"Set/unset server-authoritative physics for an account",
Content::localized("command-server_physics-desc"),
Some(Moderator),
),
ServerChatCommand::SetMotd => cmd(
vec![Any("locale", Optional), Message(Optional)],
"Set the server description",
Content::localized("command-set_motd-desc"),
Some(Admin),
),
ServerChatCommand::Ship => cmd(
@ -802,7 +814,7 @@ impl ServerChatCommand {
),
Float("destination_degrees_ccw_of_east", 90.0, Optional),
],
"Spawns a ship",
Content::localized("command-ship-desc"),
Some(Admin),
),
// Uses Message because site names can contain spaces,
@ -812,7 +824,7 @@ impl ServerChatCommand {
SiteName(Required),
Boolean("Dismount from ship", "true".to_string(), Optional),
],
"Teleport to a site",
Content::localized("command-site-desc"),
Some(Moderator),
),
ServerChatCommand::SkillPoint => cmd(
@ -820,12 +832,12 @@ impl ServerChatCommand {
Enum("skill tree", SKILL_TREES.clone(), Required),
Integer("amount", 1, Optional),
],
"Give yourself skill points for a particular skill tree",
Content::localized("command-skill_point-desc"),
Some(Admin),
),
ServerChatCommand::SkillPreset => cmd(
vec![Enum("preset_name", PRESET_LIST.to_vec(), Required)],
"Gives your character desired skills.",
Content::localized("command-skill_preset-desc"),
Some(Admin),
),
ServerChatCommand::Spawn => cmd(
@ -837,27 +849,27 @@ impl ServerChatCommand {
Float("scale", 1.0, Optional),
Boolean("tethered", "false".to_string(), Optional),
],
"Spawn a test entity",
Content::localized("command-spawn-desc"),
Some(Admin),
),
ServerChatCommand::Sudo => cmd(
vec![EntityTarget(Required), SubCommand],
"Run command as if you were another entity",
Content::localized("command-sudo-desc"),
Some(Moderator),
),
ServerChatCommand::Tell => cmd(
vec![PlayerName(Required), Message(Optional)],
"Send a message to another player",
Content::localized("command-tell-desc"),
None,
),
ServerChatCommand::Time => cmd(
vec![Enum("time", TIMES.clone(), Optional)],
"Set the time of day",
Content::localized("command-time-desc"),
Some(Admin),
),
ServerChatCommand::TimeScale => cmd(
vec![Float("time scale", 1.0, Optional)],
"Set scaling of delta time",
Content::localized("command-time_scale-desc"),
Some(Admin),
),
ServerChatCommand::Tp => cmd(
@ -865,7 +877,7 @@ impl ServerChatCommand {
EntityTarget(Optional),
Boolean("Dismount from ship", "true".to_string(), Optional),
],
"Teleport to another entity",
Content::localized("command-tp-desc"),
Some(Moderator),
),
ServerChatCommand::RtsimTp => cmd(
@ -873,18 +885,17 @@ impl ServerChatCommand {
Integer("npc index", 0, Required),
Boolean("Dismount from ship", "true".to_string(), Optional),
],
"Teleport to an rtsim npc",
Content::localized("command-rtsim_tp-desc"),
Some(Admin),
),
ServerChatCommand::RtsimInfo => cmd(
vec![Integer("npc index", 0, Required)],
"Display information about an rtsim NPC",
Content::localized("command-rtsim_info-desc"),
Some(Admin),
),
ServerChatCommand::RtsimNpc => cmd(
vec![Any("query", Required), Integer("max number", 20, Optional)],
"List rtsim NPCs that fit a given query (e.g: simulated,merchant) in order of \
distance",
Content::localized("command-rtsim_npc-desc"),
Some(Admin),
),
ServerChatCommand::RtsimPurge => cmd(
@ -893,52 +904,60 @@ impl ServerChatCommand {
true.to_string(),
Required,
)],
"Purge rtsim data on next startup",
Content::localized("command-rtsim_purge-desc"),
Some(Admin),
),
ServerChatCommand::RtsimChunk => cmd(
vec![],
"Display information about the current chunk from rtsim",
Content::localized("command-rtsim_chunk-desc"),
Some(Admin),
),
ServerChatCommand::Unban => cmd(
vec![PlayerName(Required)],
"Remove the ban for the given username",
Content::localized("command-unban-desc"),
Some(Moderator),
),
ServerChatCommand::Version => cmd(vec![], "Prints server version", None),
ServerChatCommand::Version => {
cmd(vec![], Content::localized("command-version-desc"), None)
},
ServerChatCommand::Waypoint => cmd(
vec![],
"Set your waypoint to your current position",
Content::localized("command-waypoint-desc"),
Some(Admin),
),
ServerChatCommand::Wiring => cmd(
vec![],
Content::localized("command-wiring-desc"),
Some(Admin),
),
ServerChatCommand::Wiring => cmd(vec![], "Create wiring element", Some(Admin)),
ServerChatCommand::Whitelist => cmd(
vec![Any("add/remove", Required), PlayerName(Required)],
"Adds/removes username to whitelist",
Content::localized("command-whitelist-desc"),
Some(Moderator),
),
ServerChatCommand::World => cmd(
vec![Message(Optional)],
"Send messages to everyone on the server",
Content::localized("command-world-desc"),
None,
),
ServerChatCommand::MakeVolume => cmd(
vec![Integer("size", 15, Optional)],
"Create a volume (experimental)",
Content::localized("command-make_volume-desc"),
Some(Admin),
),
ServerChatCommand::Location => {
cmd(vec![Any("name", Required)], "Teleport to a location", None)
},
ServerChatCommand::Location => cmd(
vec![Any("name", Required)],
Content::localized("command-location-desc"),
None,
),
ServerChatCommand::CreateLocation => cmd(
vec![Any("name", Required)],
"Create a location at the current position",
Content::localized("command-create_location-desc"),
Some(Moderator),
),
ServerChatCommand::DeleteLocation => cmd(
vec![Any("name", Required)],
"Delete a location",
Content::localized("command-delete_location-desc"),
Some(Moderator),
),
ServerChatCommand::WeatherZone => cmd(
@ -947,40 +966,48 @@ impl ServerChatCommand {
Float("radius", 500.0, Optional),
Float("time", 300.0, Optional),
],
"Create a weather zone",
Content::localized("command-weather_zone-desc"),
Some(Admin),
),
ServerChatCommand::Lightning => cmd(
vec![],
Content::localized("command-lightning-desc"),
Some(Admin),
),
ServerChatCommand::Lightning => {
cmd(vec![], "Lightning strike at current position", Some(Admin))
},
ServerChatCommand::Scale => cmd(
vec![
Float("factor", 1.0, Required),
Boolean("reset_mass", true.to_string(), Optional),
],
"Scale your character",
Content::localized("command-scale-desc"),
Some(Admin),
),
ServerChatCommand::RepairEquipment => cmd(
vec![],
Content::localized("command-repair_equipment-desc"),
Some(Admin),
),
ServerChatCommand::RepairEquipment => {
cmd(vec![], "Repairs all equipped items", Some(Admin))
},
ServerChatCommand::Tether => cmd(
vec![
EntityTarget(Required),
Boolean("automatic length", "true".to_string(), Optional),
],
"Tether another entity to yourself",
Content::localized("command-tether-desc"),
Some(Admin),
),
ServerChatCommand::DestroyTethers => cmd(
vec![],
Content::localized("command-destroy_tethers-desc"),
Some(Admin),
),
ServerChatCommand::Mount => cmd(
vec![EntityTarget(Required)],
Content::localized("command-mount-desc"),
Some(Admin),
),
ServerChatCommand::DestroyTethers => {
cmd(vec![], "Destroy all tethers connected to you", Some(Admin))
},
ServerChatCommand::Mount => {
cmd(vec![EntityTarget(Required)], "Mount an entity", Some(Admin))
},
ServerChatCommand::Dismount => cmd(
vec![EntityTarget(Required)],
"Dismount if you are riding, or dismount anything riding you",
Content::localized("command-dismount-desc"),
Some(Admin),
),
}
@ -1019,7 +1046,6 @@ impl ServerChatCommand {
ServerChatCommand::GroupLeave => "group_leave",
ServerChatCommand::GroupPromote => "group_promote",
ServerChatCommand::Health => "health",
ServerChatCommand::Help => "help",
ServerChatCommand::IntoNpc => "into_npc",
ServerChatCommand::JoinFaction => "join_faction",
ServerChatCommand::Jump => "jump",
@ -1102,13 +1128,18 @@ impl ServerChatCommand {
pub fn iter() -> impl Iterator<Item = Self> + Clone { <Self as IntoEnumIterator>::iter() }
/// A message that explains what the command does
pub fn help_string(&self) -> String {
pub fn help_content(&self) -> Content {
let data = self.data();
let usage = std::iter::once(format!("/{}", self.keyword()))
.chain(data.args.iter().map(|arg| arg.usage_string()))
.collect::<Vec<_>>()
.join(" ");
format!("{}: {}", usage, data.description)
Content::localized_with_args("command-help-template", [
("usage", Content::Plain(usage)),
("description", data.description),
])
}
/// Produce an iterator that first goes over all the short keywords

View File

@ -166,7 +166,6 @@ fn do_command(
ServerChatCommand::GroupLeave => handle_group_leave,
ServerChatCommand::GroupPromote => handle_group_promote,
ServerChatCommand::Health => handle_health,
ServerChatCommand::Help => handle_help,
ServerChatCommand::IntoNpc => handle_into_npc,
ServerChatCommand::JoinFaction => handle_join_faction,
ServerChatCommand::Jump => handle_jump,
@ -604,7 +603,7 @@ fn handle_give_item(
)]))
}
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -638,7 +637,7 @@ fn handle_make_block(
))
}
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -662,7 +661,7 @@ fn handle_into_npc(
}
let Some(entity_config) = parse_cmd_args!(args, String) else {
return Err(Content::Plain(action.help_string()));
return Err(action.help_content());
};
let config = match EntityConfig::load(&entity_config) {
@ -711,7 +710,7 @@ fn handle_make_npc(
) -> CmdResult<()> {
let (entity_config, number) = parse_cmd_args!(args, String, i8);
let entity_config = entity_config.ok_or_else(|| action.help_string())?;
let entity_config = entity_config.ok_or_else(|| action.help_content())?;
let number = match number {
// Number of entities must be larger than 1
Some(i8::MIN..=0) => {
@ -815,7 +814,7 @@ fn handle_make_sprite(
)]))
}
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -903,7 +902,7 @@ fn handle_set_motd(
unreachable!("edit always returns Some")
})
},
_ => Err(Content::Plain(action.help_string())),
_ => Err(action.help_content()),
}
}
@ -922,7 +921,7 @@ fn handle_jump(
current_pos.0 += Vec3::new(x, y, z)
})
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -941,7 +940,7 @@ fn handle_goto(
current_pos.0 = Vec3::new(x, y, z)
})
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -989,7 +988,7 @@ fn handle_site(
current_pos.0 = site_pos
})
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -1366,7 +1365,7 @@ fn handle_alias(
}
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -1383,7 +1382,7 @@ fn handle_tp(
} else if client != target {
client
} else {
return Err(Content::Plain(action.help_string()));
return Err(action.help_content());
};
let player_pos = position(server, player, "player")?;
server
@ -1415,7 +1414,7 @@ fn handle_rtsim_tp(
.ok_or_else(|| format!("No NPC has the id {id}"))?
.wpos
} else {
return Err(Content::Plain(action.help_string()));
return Err(action.help_content());
};
server
.state
@ -1479,7 +1478,7 @@ fn handle_rtsim_info(
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -1551,7 +1550,7 @@ fn handle_rtsim_npc(
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -1588,7 +1587,7 @@ fn handle_rtsim_purge(
);
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -1780,7 +1779,7 @@ fn handle_spawn(
);
Ok(())
},
_ => Err(Content::Plain(action.help_string())),
_ => Err(action.help_content()),
}
}
@ -2045,7 +2044,7 @@ fn handle_clear_persisted_terrain(
action: &ServerChatCommand,
) -> CmdResult<()> {
let Some(radius) = parse_cmd_args!(args, i32) else {
return Err(Content::Plain(action.help_string()));
return Err(action.help_content());
};
// Clamp the radius to prevent accidentally passing too large radiuses
let radius = radius.clamp(0, 64);
@ -2148,7 +2147,7 @@ fn handle_permit_build(
);
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -2189,7 +2188,7 @@ fn handle_revoke_build(
Err(Content::localized("command-no-buid-perms"))
}
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -2279,7 +2278,7 @@ fn handle_spawn_portal(
);
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -2364,7 +2363,7 @@ fn handle_area_add(
server.notify_client(client, msg);
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -2433,48 +2432,10 @@ fn handle_area_remove(
);
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
fn handle_help(
server: &mut Server,
client: EcsEntity,
_target: EcsEntity,
args: Vec<String>,
_action: &ServerChatCommand,
) -> CmdResult<()> {
if let Some(cmd) = parse_cmd_args!(args, ServerChatCommand) {
server.notify_client(
client,
ServerGeneral::server_msg(ChatType::CommandInfo, cmd.help_string()),
)
} else {
let mut message = String::new();
let entity_role = server.entity_admin_role(client);
// Iterate through all commands you have permission to use.
ServerChatCommand::iter()
.filter(|cmd| cmd.needs_role() <= entity_role)
.for_each(|cmd| {
message += &cmd.help_string();
message += "\n";
});
message += "Additionally, you can use the following shortcuts:";
ServerChatCommand::iter()
.filter_map(|cmd| cmd.short_keyword().map(|k| (k, cmd)))
.for_each(|(k, cmd)| {
message += &format!(" /{} => /{}", k, cmd.keyword());
});
server.notify_client(
client,
ServerGeneral::server_msg(ChatType::CommandInfo, message),
)
}
Ok(())
}
fn parse_alignment(owner: Uid, alignment: &str) -> CmdResult<Alignment> {
match alignment {
"wild" => Ok(Alignment::Wild),
@ -2632,7 +2593,7 @@ fn handle_kit(
ServerGeneral::server_msg(ChatType::CommandInfo, format!("Gave kit: {}", kit_name)),
);
};
let name = parse_cmd_args!(args, String).ok_or_else(|| action.help_string())?;
let name = parse_cmd_args!(args, String).ok_or_else(|| action.help_content())?;
match name.as_str() {
"all" => {
@ -2910,7 +2871,7 @@ fn handle_lantern(
Err(Content::localized("command-lantern-unequiped"))
}
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -3090,7 +3051,7 @@ fn handle_adminify(
"admin" => AdminRole::Admin,
"moderator" => AdminRole::Moderator,
_ => {
return Err(Content::Plain(action.help_string()));
return Err(action.help_content());
},
})
} else {
@ -3182,7 +3143,7 @@ fn handle_adminify(
server.state.notify_players(msg);
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -3221,7 +3182,7 @@ fn handle_tell(
server.notify_client(target, ServerGeneral::ChatMode(mode));
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -3317,7 +3278,7 @@ fn handle_group_invite(
);
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -3338,7 +3299,7 @@ fn handle_group_kick(
.emit_event_now(GroupManipEvent(target, comp::GroupManip::Kick(uid)));
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -3372,7 +3333,7 @@ fn handle_group_promote(
.emit_event_now(GroupManipEvent(target, comp::GroupManip::AssignLeader(uid)));
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -3393,7 +3354,7 @@ fn handle_reset_recipes(
server.notify_client(target, ServerGeneral::UpdateRecipes);
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -3724,7 +3685,7 @@ fn handle_skill_point(
Err("Entity has no stats!".into())
}
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -3918,7 +3879,7 @@ fn handle_sudo(
Err(Content::localized("command-unknown"))
}
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -4008,10 +3969,10 @@ fn handle_whitelist(
});
edit_setting_feedback(server, client, edit, || format!("{}{}", err_info, username))
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -4067,7 +4028,7 @@ fn handle_kick(
);
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -4145,7 +4106,7 @@ fn handle_ban(
}
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -4161,7 +4122,7 @@ fn handle_aura(
let (Some(aura_radius), aura_duration, new_entity, aura_target, Some(aura_kind_variant), spec) =
parse_cmd_args!(args, f32, f32, bool, GroupTarget, AuraKindVariant, ..Vec<String>)
else {
return Err(Content::Plain(action.help_string()));
return Err(action.help_content());
};
let new_entity = new_entity.unwrap_or(false);
let aura_kind = match aura_kind_variant {
@ -4377,7 +4338,7 @@ fn handle_battlemode_force(
if !settings.gameplay.battle_mode.allow_choosing() {
return Err(Content::localized("command-disabled-by-settings"));
}
let mode = parse_cmd_args!(args, String).ok_or_else(|| action.help_string())?;
let mode = parse_cmd_args!(args, String).ok_or_else(|| action.help_content())?;
let mode = match mode.as_str() {
"pvp" => BattleMode::PvP,
"pve" => BattleMode::PvE,
@ -4442,7 +4403,7 @@ fn handle_unban(
format!("{} was already unbanned", username)
})
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -4474,7 +4435,7 @@ fn handle_server_physics(
);
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -4488,7 +4449,7 @@ fn handle_buff(
let (Some(buff), strength, duration, misc_data_spec) =
parse_cmd_args!(args, String, f32, f64, String)
else {
return Err(Content::Plain(action.help_string()));
return Err(action.help_content());
};
let strength = strength.unwrap_or(0.01);
@ -4656,7 +4617,7 @@ fn handle_skill_preset(
Err("Player has no stats!".into())
}
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -4755,7 +4716,7 @@ fn handle_create_location(
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -4782,7 +4743,7 @@ fn handle_delete_location(
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -4866,7 +4827,7 @@ fn handle_weather_zone(
_ => Err(Content::localized("command-weather-valid-values")),
}
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -4910,7 +4871,7 @@ fn handle_body(
}
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -4946,7 +4907,7 @@ fn handle_scale(
);
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -4978,7 +4939,7 @@ fn handle_repair_equipment(
);
Ok(())
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -5037,7 +4998,7 @@ fn handle_tether(
Err("Tether members don't have Uids.".into())
}
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}
@ -5097,7 +5058,7 @@ fn handle_mount(
Err("Mount and/or rider doesn't have an Uid component.".into())
}
} else {
Err(Content::Plain(action.help_string()))
Err(action.help_content())
}
}

View File

@ -56,6 +56,7 @@ common-assets = { package = "veloren-common-assets", path = "../common/assets",
common-base = { package = "veloren-common-base", path = "../common/base" }
common-ecs = { package = "veloren-common-ecs", path = "../common/ecs" }
common-frontend = { package = "veloren-common-frontend", path = "../common/frontend" }
common-i18n = { package = "veloren-common-i18n", path = "../common/i18n" }
common-net = { package = "veloren-common-net", path = "../common/net" }
common-state = { package = "veloren-common-state", path = "../common/state" }
common-systems = { package = "veloren-common-systems", path = "../common/systems" }

View File

@ -1,9 +1,14 @@
use common::cmd::{ChatCommandData, ServerChatCommand};
use i18n::{LocalizationGuard, LocalizationHandle};
use veloren_voxygen::cmd::ClientChatCommand;
/// This binary generates the markdown tables used for the `players/commands.md`
/// page in the Veloren Book. It can be run with `cargo cmd-doc-gen`.
fn main() {
let i18n = LocalizationHandle::load(i18n::REFERENCE_LANG)
.unwrap()
.read();
let table_header = "|Command|Description|Requires|Arguments|";
let table_seperator = "|-|-|-|-|";
@ -11,7 +16,7 @@ fn main() {
println!("{table_seperator}");
for cmd in ServerChatCommand::iter() {
println!("{}", format_row(cmd.keyword(), &cmd.data()))
println!("{}", format_row(cmd.keyword(), &cmd.data(), &i18n))
}
println!();
@ -20,11 +25,11 @@ fn main() {
println!("{table_seperator}");
for cmd in ClientChatCommand::iter() {
println!("{}", format_row(cmd.keyword(), &cmd.data()))
println!("{}", format_row(cmd.keyword(), &cmd.data(), &i18n))
}
}
fn format_row(keyword: &str, data: &ChatCommandData) -> String {
fn format_row(keyword: &str, data: &ChatCommandData, i18n: &LocalizationGuard) -> String {
let args = data
.args
.iter()
@ -35,7 +40,7 @@ fn format_row(keyword: &str, data: &ChatCommandData) -> String {
format!(
"|/{}|{}|{}|{}|",
keyword,
data.description,
i18n.get_content(&data.description),
data.needs_role
.map_or("".to_string(), |role| format!("{:?}", role)),
if !args.is_empty() {

View File

@ -16,6 +16,7 @@ use common::{
uid::Uid,
uuid::Uuid,
};
use common_i18n::Content;
use common_net::sync::WorldSyncExt;
use itertools::Itertools;
use levenshtein::levenshtein;
@ -38,11 +39,9 @@ impl ClientChatCommand {
use Requirement::*;
let cmd = ChatCommandData::new;
match self {
ClientChatCommand::Clear => cmd(
Vec::new(),
"Clears all messages in chat. Affects all chat tabs.",
None,
),
ClientChatCommand::Clear => {
cmd(Vec::new(), Content::localized("command-clear-desc"), None)
},
ClientChatCommand::ExperimentalShader => cmd(
vec![Enum(
"Shader",
@ -51,22 +50,22 @@ impl ClientChatCommand {
.collect(),
Optional,
)],
"Toggles an experimental shader.",
Content::localized("command-experimental_shader-desc"),
None,
),
ClientChatCommand::Help => cmd(
vec![Command(Optional)],
"Display information about commands",
Content::localized("command-help-desc"),
None,
),
ClientChatCommand::Mute => cmd(
vec![PlayerName(Required)],
"Mutes chat messages from a player.",
Content::localized("command-mute-desc"),
None,
),
ClientChatCommand::Unmute => cmd(
vec![PlayerName(Required)],
"Unmutes a player muted with the 'mute' command.",
Content::localized("command-unmute-desc"),
None,
),
}
@ -83,13 +82,18 @@ impl ClientChatCommand {
}
/// A message that explains what the command does
pub fn help_string(&self) -> String {
pub fn help_content(&self) -> Content {
let data = self.data();
let usage = std::iter::once(format!("/{}", self.keyword()))
.chain(data.args.iter().map(|arg| arg.usage_string()))
.collect::<Vec<_>>()
.join(" ");
format!("{}: {}", usage, data.description)
Content::localized_with_args("command-help-template", [
("usage", Content::Plain(usage)),
("description", data.description),
])
}
/// Returns a format string for parsing arguments with scan_fmt
@ -377,13 +381,15 @@ fn handle_clear(
fn handle_help(
session_state: &mut SessionState,
_global_state: &mut GlobalState,
global_state: &mut GlobalState,
args: Vec<String>,
) -> CommandResult {
let i18n = global_state.i18n.read();
if let Some(cmd) = parse_cmd_args!(&args, ServerChatCommand) {
Ok(Some(cmd.help_string()))
Ok(Some(i18n.get_content(&cmd.help_content())))
} else if let Some(cmd) = parse_cmd_args!(&args, ClientChatCommand) {
Ok(Some(cmd.help_string()))
Ok(Some(i18n.get_content(&cmd.help_content())))
} else {
let client = &mut session_state.client.borrow_mut();
@ -395,17 +401,17 @@ fn handle_help(
.map(|admin| admin.0);
ClientChatCommand::iter().for_each(|cmd| {
message += &cmd.help_string();
message += &i18n.get_content(&cmd.help_content());
message += "\n";
});
// Iterate through all ServerChatCommands you have permission to use.
ServerChatCommand::iter()
.filter(|cmd| cmd.needs_role() <= entity_role)
.for_each(|cmd| {
message += &cmd.help_string();
message += &i18n.get_content(&cmd.help_content());
message += "\n";
});
message += "Additionally, you can use the following shortcuts:";
message += &i18n.get_msg("command-help-additional-shortcuts");
ServerChatCommand::iter()
.filter(|cmd| cmd.needs_role() <= entity_role)
.filter_map(|cmd| cmd.short_keyword().map(|k| (k, cmd)))