Skip to main content

steel_core/command/execution/
world.rs

1//! Loaded-world command arguments.
2
3use std::{fmt, sync::Arc};
4
5use steel_utils::{Identifier, translations};
6
7use super::{CommandArgumentSource, CommandSource, argument::parse_identifier};
8use crate::{
9    command::brigadier::{CommandSyntaxError, StringReader, SuggestionsBuilder},
10    world::World,
11};
12
13/// A fully qualified world key or a world path relative to the source domain.
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub(crate) enum WorldArgument {
16    Key(Identifier),
17    Relative(Box<str>),
18}
19
20impl WorldArgument {
21    pub(crate) fn resolve(&self, source: &CommandSource) -> Result<Arc<World>, CommandSyntaxError> {
22        let world = match self {
23            Self::Key(key) => source.server().worlds.get(key),
24            Self::Relative(path) => {
25                let key = Identifier::new(source.world().domain().to_owned(), path.to_string());
26                source.server().worlds.get(&key)
27            }
28        };
29        world.map_or_else(
30            || {
31                let message = translations::ARGUMENT_DIMENSION_INVALID
32                    .message([self.to_string()])
33                    .component();
34                Err(CommandSyntaxError::dynamic(message))
35            },
36            |world| Ok(Arc::clone(world)),
37        )
38    }
39}
40
41impl fmt::Display for WorldArgument {
42    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
43        match self {
44            Self::Key(key) => write!(formatter, "{key}"),
45            Self::Relative(path) => formatter.write_str(path),
46        }
47    }
48}
49
50pub(super) fn parse_world_argument(
51    reader: &mut StringReader<'_>,
52) -> Result<WorldArgument, CommandSyntaxError> {
53    let start_byte = reader.read_so_far().len();
54    let key = parse_identifier(reader)?;
55    let raw = &reader.read_so_far()[start_byte..];
56    if raw.contains(':') {
57        Ok(WorldArgument::Key(key))
58    } else {
59        Ok(WorldArgument::Relative(key.path.to_string().into()))
60    }
61}
62
63pub(super) fn suggest_worlds<S>(builder: &mut SuggestionsBuilder<'_>, source: &S)
64where
65    S: CommandArgumentSource + ?Sized,
66{
67    let prefix = builder.remaining_lowercase().to_owned();
68    for world in source
69        .command_world_names()
70        .into_iter()
71        .filter(|world| world.starts_with(&prefix))
72    {
73        builder.suggest(world);
74    }
75}