mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Implement tab completion of enums (/object /time /spawn) and numbers
This commit is contained in:
parent
28e94afd3f
commit
b486de28ac
@ -57,17 +57,10 @@ impl From<std::io::Error> for Error {
|
||||
|
||||
lazy_static! {
|
||||
/// The HashMap where all loaded assets are stored in.
|
||||
static ref ASSETS: RwLock<HashMap<String, Arc<dyn Any + 'static + Sync + Send>>> =
|
||||
pub static ref ASSETS: RwLock<HashMap<String, Arc<dyn Any + 'static + Sync + Send>>> =
|
||||
RwLock::new(HashMap::new());
|
||||
}
|
||||
|
||||
const ASSETS_TMP: [&'static str; 1] = ["common/items/lantern/black_0"];
|
||||
pub fn iterate() -> impl Iterator<Item = &'static str> {
|
||||
// TODO FIXME implement this
|
||||
//ASSETS.read().iter().flat_map(|e| e.keys())
|
||||
ASSETS_TMP.iter().map(|k| *k)
|
||||
}
|
||||
|
||||
// TODO: Remove this function. It's only used in world/ in a really ugly way.To
|
||||
// do this properly assets should have all their necessary data in one file. A
|
||||
// ron file could be used to combine voxel data with positioning data for
|
||||
|
@ -1,5 +1,7 @@
|
||||
use crate::{assets, comp::Player, state::State};
|
||||
use crate::{assets, comp, npc, state::State};
|
||||
use lazy_static::lazy_static;
|
||||
use specs::prelude::{Join, WorldExt};
|
||||
use std::{ops::Deref, str::FromStr};
|
||||
|
||||
/// Struct representing a command that a user can run from server chat.
|
||||
pub struct ChatCommandData {
|
||||
@ -85,63 +87,108 @@ pub static CHAT_COMMANDS: &'static [ChatCommand] = &[
|
||||
ChatCommand::Waypoint,
|
||||
];
|
||||
|
||||
lazy_static! {
|
||||
static ref ALIGNMENTS: Vec<String> = vec!["wild", "enemy", "npc", "pet"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
static ref ENTITIES: Vec<String> = {
|
||||
let npc_names = &*npc::NPC_NAMES;
|
||||
npc::ALL_NPCS
|
||||
.iter()
|
||||
.map(|&npc| npc_names[npc].keyword.clone())
|
||||
.collect()
|
||||
};
|
||||
static ref OBJECTS: Vec<String> = comp::object::ALL_OBJECTS
|
||||
.iter()
|
||||
.map(|o| o.to_string().to_string())
|
||||
.collect();
|
||||
static ref TIMES: Vec<String> = vec![
|
||||
"midnight", "night", "dawn", "morning", "day", "noon", "dusk"
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
}
|
||||
fn items() -> Vec<String> {
|
||||
if let Ok(assets) = assets::ASSETS.read() {
|
||||
assets
|
||||
.iter()
|
||||
.flat_map(|(k, v)| {
|
||||
if v.is::<comp::item::Item>() {
|
||||
Some(k.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
error!("Assets not found");
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl ChatCommand {
|
||||
pub fn data(&self) -> ChatCommandData {
|
||||
use ArgumentSpec::*;
|
||||
use Requirement::*;
|
||||
let cmd = ChatCommandData::new;
|
||||
match self {
|
||||
ChatCommand::Adminify => cmd(
|
||||
vec![PlayerName(false)],
|
||||
vec![PlayerName(Required)],
|
||||
"Temporarily gives a player admin permissions or removes them",
|
||||
true,
|
||||
),
|
||||
ChatCommand::Alias => cmd(vec![Any("name", false)], "Change your alias", false),
|
||||
ChatCommand::Alias => cmd(vec![Any("name", Required)], "Change your alias", false),
|
||||
ChatCommand::Build => cmd(vec![], "Toggles build mode on and off", true),
|
||||
ChatCommand::Debug => cmd(vec![], "Place all debug items into your pack.", true),
|
||||
ChatCommand::DebugColumn => cmd(
|
||||
vec![Float("x", f32::NAN, false), Float("y", f32::NAN, false)],
|
||||
vec![
|
||||
Integer("x", 15000, Required),
|
||||
Integer("y", 15000, Required),
|
||||
],
|
||||
"Prints some debug information about a column",
|
||||
false,
|
||||
),
|
||||
ChatCommand::Explosion => cmd(
|
||||
vec![Float("radius", 5.0, false)],
|
||||
vec![Float("radius", 5.0, Required)],
|
||||
"Explodes the ground around you",
|
||||
true,
|
||||
),
|
||||
ChatCommand::GiveExp => cmd(
|
||||
vec![Integer("amount", 50, false)],
|
||||
vec![Integer("amount", 50, Required)],
|
||||
"Give experience to yourself",
|
||||
true,
|
||||
),
|
||||
ChatCommand::GiveItem => cmd(
|
||||
vec![ItemSpec(false), Integer("num", 1, true)],
|
||||
vec![Enum("item", items(), Required), Integer("num", 1, Optional)],
|
||||
"Give yourself some items",
|
||||
true,
|
||||
),
|
||||
ChatCommand::Goto => cmd(
|
||||
vec![
|
||||
Float("x", 0.0, false),
|
||||
Float("y", 0.0, false),
|
||||
Float("z", 0.0, false),
|
||||
Float("x", 0.0, Required),
|
||||
Float("y", 0.0, Required),
|
||||
Float("z", 0.0, Required),
|
||||
],
|
||||
"Teleport to a position",
|
||||
true,
|
||||
),
|
||||
ChatCommand::Health => cmd(
|
||||
vec![Integer("hp", 100, false)],
|
||||
vec![Integer("hp", 100, Required)],
|
||||
"Set your current health",
|
||||
true,
|
||||
),
|
||||
ChatCommand::Help => ChatCommandData::new(
|
||||
vec![Command(true)],
|
||||
vec![Command(Optional)],
|
||||
"Display information about commands",
|
||||
false,
|
||||
),
|
||||
ChatCommand::Jump => cmd(
|
||||
vec![
|
||||
Float("x", 0.0, false),
|
||||
Float("y", 0.0, false),
|
||||
Float("z", 0.0, false),
|
||||
Float("x", 0.0, Required),
|
||||
Float("y", 0.0, Required),
|
||||
Float("z", 0.0, Required),
|
||||
],
|
||||
"Offset your current position",
|
||||
true,
|
||||
@ -150,50 +197,72 @@ impl ChatCommand {
|
||||
ChatCommand::KillNpcs => cmd(vec![], "Kill the NPCs", true),
|
||||
ChatCommand::Lantern => cmd(
|
||||
vec![
|
||||
Float("strength", 5.0, false),
|
||||
Float("r", 1.0, true),
|
||||
Float("g", 1.0, true),
|
||||
Float("b", 1.0, true),
|
||||
Float("strength", 5.0, Required),
|
||||
Float("r", 1.0, Optional),
|
||||
Float("g", 1.0, Optional),
|
||||
Float("b", 1.0, Optional),
|
||||
],
|
||||
"Change your lantern's strength and color",
|
||||
true,
|
||||
),
|
||||
ChatCommand::Light => cmd(
|
||||
vec![
|
||||
Float("r", 1.0, true),
|
||||
Float("g", 1.0, true),
|
||||
Float("b", 1.0, true),
|
||||
Float("x", 0.0, true),
|
||||
Float("y", 0.0, true),
|
||||
Float("z", 0.0, true),
|
||||
Float("strength", 5.0, true),
|
||||
Float("r", 1.0, Optional),
|
||||
Float("g", 1.0, Optional),
|
||||
Float("b", 1.0, Optional),
|
||||
Float("x", 0.0, Optional),
|
||||
Float("y", 0.0, Optional),
|
||||
Float("z", 0.0, Optional),
|
||||
Float("strength", 5.0, Optional),
|
||||
],
|
||||
"Spawn entity with light",
|
||||
true,
|
||||
),
|
||||
ChatCommand::Object => cmd(vec![/*TODO*/], "Spawn an object", true),
|
||||
ChatCommand::Object => cmd(
|
||||
vec![Enum("object", OBJECTS.clone(), Required)],
|
||||
"Spawn an object",
|
||||
true,
|
||||
),
|
||||
ChatCommand::Players => cmd(vec![], "Lists players currently online", false),
|
||||
ChatCommand::RemoveLights => cmd(
|
||||
vec![Float("radius", 20.0, true)],
|
||||
vec![Float("radius", 20.0, Optional)],
|
||||
"Removes all lights spawned by players",
|
||||
true,
|
||||
),
|
||||
ChatCommand::SetLevel => {
|
||||
cmd(vec![Integer("level", 10, false)], "Set player Level", true)
|
||||
},
|
||||
ChatCommand::Spawn => cmd(vec![/*TODO*/], "Spawn a test entity", true),
|
||||
ChatCommand::SetLevel => cmd(
|
||||
vec![Integer("level", 10, Required)],
|
||||
"Set player Level",
|
||||
true,
|
||||
),
|
||||
ChatCommand::Spawn => cmd(
|
||||
vec![
|
||||
Enum("alignment", ALIGNMENTS.clone(), Required),
|
||||
Enum("entity", ENTITIES.clone(), Required),
|
||||
Integer("amount", 1, Optional),
|
||||
],
|
||||
"Spawn a test entity",
|
||||
true,
|
||||
),
|
||||
ChatCommand::Sudo => cmd(
|
||||
vec![PlayerName(false), SubCommand],
|
||||
vec![PlayerName(Required), SubCommand],
|
||||
"Run command as if you were another player",
|
||||
true,
|
||||
),
|
||||
ChatCommand::Tell => cmd(
|
||||
vec![PlayerName(false), Message],
|
||||
vec![PlayerName(Required), Message],
|
||||
"Send a message to another player",
|
||||
false,
|
||||
),
|
||||
ChatCommand::Time => cmd(vec![/*TODO*/], "Set the time of day", true),
|
||||
ChatCommand::Tp => cmd(vec![PlayerName(true)], "Teleport to another player", true),
|
||||
ChatCommand::Time => cmd(
|
||||
vec![Enum("time", TIMES.clone(), Optional)],
|
||||
"Set the time of day",
|
||||
true,
|
||||
),
|
||||
ChatCommand::Tp => cmd(
|
||||
vec![PlayerName(Optional)],
|
||||
"Teleport to another player",
|
||||
true,
|
||||
),
|
||||
ChatCommand::Version => cmd(vec![], "Prints server version", false),
|
||||
ChatCommand::Waypoint => {
|
||||
cmd(vec![], "Set your waypoint to your current position", true)
|
||||
@ -250,21 +319,20 @@ impl ChatCommand {
|
||||
.iter()
|
||||
.map(|arg| match arg {
|
||||
ArgumentSpec::PlayerName(_) => "{}",
|
||||
ArgumentSpec::ItemSpec(_) => "{}",
|
||||
ArgumentSpec::Float(_, _, _) => "{}",
|
||||
ArgumentSpec::Integer(_, _, _) => "{d}",
|
||||
ArgumentSpec::Any(_, _) => "{}",
|
||||
ArgumentSpec::Command(_) => "{}",
|
||||
ArgumentSpec::Message => "{/.*/}",
|
||||
ArgumentSpec::SubCommand => "{} {/.*/}",
|
||||
ArgumentSpec::OneOf(_, _, _, _) => "{}", // TODO
|
||||
ArgumentSpec::Enum(_, _, _) => "{}", // TODO
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for ChatCommand {
|
||||
impl FromStr for ChatCommand {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(keyword: &str) -> Result<ChatCommand, ()> {
|
||||
@ -282,26 +350,39 @@ impl std::str::FromStr for ChatCommand {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Requirement {
|
||||
Required,
|
||||
Optional,
|
||||
}
|
||||
impl Deref for Requirement {
|
||||
type Target = bool;
|
||||
|
||||
fn deref(&self) -> &bool {
|
||||
match self {
|
||||
Requirement::Required => &true,
|
||||
Requirement::Optional => &false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Representation for chat command arguments
|
||||
pub enum ArgumentSpec {
|
||||
/// The argument refers to a player by alias
|
||||
PlayerName(bool),
|
||||
/// The argument refers to an item asset by path
|
||||
ItemSpec(bool),
|
||||
PlayerName(Requirement),
|
||||
/// The argument is a float. The associated values are
|
||||
/// * label
|
||||
/// * default tab-completion
|
||||
/// * suggested tab-completion
|
||||
/// * whether it's optional
|
||||
Float(&'static str, f32, bool),
|
||||
Float(&'static str, f32, Requirement),
|
||||
/// The argument is a float. The associated values are
|
||||
/// * label
|
||||
/// * default tab-completion
|
||||
/// * suggested tab-completion
|
||||
/// * whether it's optional
|
||||
Integer(&'static str, i32, bool),
|
||||
Integer(&'static str, i32, Requirement),
|
||||
/// The argument is any string that doesn't contain spaces
|
||||
Any(&'static str, bool),
|
||||
/// The argument is a command name
|
||||
Command(bool),
|
||||
Any(&'static str, Requirement),
|
||||
/// The argument is a command name (such as in /help)
|
||||
Command(Requirement),
|
||||
/// This is the final argument, consuming all characters until the end of
|
||||
/// input.
|
||||
Message,
|
||||
@ -310,68 +391,55 @@ pub enum ArgumentSpec {
|
||||
/// The argument is likely an enum. The associated values are
|
||||
/// * label
|
||||
/// * Predefined string completions
|
||||
/// * Other completion types
|
||||
/// * whether it's optional
|
||||
OneOf(
|
||||
&'static str,
|
||||
&'static [&'static str],
|
||||
Vec<Box<ArgumentSpec>>,
|
||||
bool,
|
||||
),
|
||||
Enum(&'static str, Vec<String>, Requirement),
|
||||
}
|
||||
|
||||
impl ArgumentSpec {
|
||||
pub fn usage_string(&self) -> String {
|
||||
match self {
|
||||
ArgumentSpec::PlayerName(optional) => {
|
||||
if *optional {
|
||||
"[player]".to_string()
|
||||
} else {
|
||||
ArgumentSpec::PlayerName(req) => {
|
||||
if **req {
|
||||
"<player>".to_string()
|
||||
} else {
|
||||
"[player]".to_string()
|
||||
}
|
||||
},
|
||||
ArgumentSpec::ItemSpec(optional) => {
|
||||
if *optional {
|
||||
"[item]".to_string()
|
||||
} else {
|
||||
"<item>".to_string()
|
||||
}
|
||||
},
|
||||
ArgumentSpec::Float(label, _, optional) => {
|
||||
if *optional {
|
||||
format!("[{}]", label)
|
||||
} else {
|
||||
ArgumentSpec::Float(label, _, req) => {
|
||||
if **req {
|
||||
format!("<{}>", label)
|
||||
}
|
||||
},
|
||||
ArgumentSpec::Integer(label, _, optional) => {
|
||||
if *optional {
|
||||
} else {
|
||||
format!("[{}]", label)
|
||||
} else {
|
||||
format!("<{}>", label)
|
||||
}
|
||||
},
|
||||
ArgumentSpec::Any(label, optional) => {
|
||||
if *optional {
|
||||
ArgumentSpec::Integer(label, _, req) => {
|
||||
if **req {
|
||||
format!("<{}>", label)
|
||||
} else {
|
||||
format!("[{}]", label)
|
||||
} else {
|
||||
format!("<{}>", label)
|
||||
}
|
||||
},
|
||||
ArgumentSpec::Command(optional) => {
|
||||
if *optional {
|
||||
"[[/]command]".to_string()
|
||||
ArgumentSpec::Any(label, req) => {
|
||||
if **req {
|
||||
format!("<{}>", label)
|
||||
} else {
|
||||
format!("[{}]", label)
|
||||
}
|
||||
},
|
||||
ArgumentSpec::Command(req) => {
|
||||
if **req {
|
||||
"<[/]command>".to_string()
|
||||
} else {
|
||||
"[[/]command]".to_string()
|
||||
}
|
||||
},
|
||||
ArgumentSpec::Message => "<message>".to_string(),
|
||||
ArgumentSpec::SubCommand => "<[/]command> [args...]".to_string(),
|
||||
ArgumentSpec::OneOf(label, _, _, optional) => {
|
||||
if *optional {
|
||||
format! {"[{}]", label}
|
||||
} else {
|
||||
ArgumentSpec::Enum(label, _, req) => {
|
||||
if **req {
|
||||
format! {"<{}>", label}
|
||||
} else {
|
||||
format! {"[{}]", label}
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -380,33 +448,35 @@ impl ArgumentSpec {
|
||||
pub fn complete(&self, part: &str, state: &State) -> Vec<String> {
|
||||
match self {
|
||||
ArgumentSpec::PlayerName(_) => complete_player(part, &state),
|
||||
ArgumentSpec::ItemSpec(_) => assets::iterate()
|
||||
.filter(|asset| asset.starts_with(part))
|
||||
.map(|c| c.to_string())
|
||||
.collect(),
|
||||
ArgumentSpec::Float(_, x, _) => vec![format!("{}", x)],
|
||||
ArgumentSpec::Integer(_, x, _) => vec![format!("{}", x)],
|
||||
ArgumentSpec::Float(_, x, _) => {
|
||||
if part.is_empty() {
|
||||
vec![format!("{:.1}", x)]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
},
|
||||
ArgumentSpec::Integer(_, x, _) => {
|
||||
if part.is_empty() {
|
||||
vec![format!("{}", x)]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
},
|
||||
ArgumentSpec::Any(_, _) => vec![],
|
||||
ArgumentSpec::Command(_) => complete_command(part),
|
||||
ArgumentSpec::Message => complete_player(part, &state),
|
||||
ArgumentSpec::SubCommand => complete_command(part),
|
||||
ArgumentSpec::OneOf(_, strings, alts, _) => {
|
||||
let string_completions = strings
|
||||
.iter()
|
||||
.filter(|string| string.starts_with(part))
|
||||
.map(|c| c.to_string());
|
||||
let alt_completions = alts
|
||||
.iter()
|
||||
.flat_map(|b| (*b).complete(part, &state))
|
||||
.map(|c| c.to_string());
|
||||
string_completions.chain(alt_completions).collect()
|
||||
},
|
||||
ArgumentSpec::Enum(_, strings, _) => strings
|
||||
.iter()
|
||||
.filter(|string| string.starts_with(part))
|
||||
.map(|c| c.to_string())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn complete_player(part: &str, state: &State) -> Vec<String> {
|
||||
let storage = state.ecs().read_storage::<Player>();
|
||||
let storage = state.ecs().read_storage::<comp::Player>();
|
||||
let mut iter = storage.join();
|
||||
if let Some(first) = iter.next() {
|
||||
std::iter::once(first)
|
||||
|
@ -65,7 +65,7 @@ impl Body {
|
||||
}
|
||||
}
|
||||
|
||||
const ALL_OBJECTS: [Body; 52] = [
|
||||
pub const ALL_OBJECTS: [Body; 53] = [
|
||||
Body::Arrow,
|
||||
Body::Bomb,
|
||||
Body::Scarecrow,
|
||||
@ -114,8 +114,69 @@ const ALL_OBJECTS: [Body; 52] = [
|
||||
Body::CarpetHumanSquare,
|
||||
Body::CarpetHumanSquare2,
|
||||
Body::CarpetHumanSquircle,
|
||||
Body::Pouch,
|
||||
Body::CraftingBench,
|
||||
Body::BoltFire,
|
||||
Body::BoltFireBig,
|
||||
Body::ArrowSnake,
|
||||
];
|
||||
|
||||
impl Body {
|
||||
pub fn to_string(&self) -> &str {
|
||||
match self {
|
||||
Body::Arrow => "arrow",
|
||||
Body::Bomb => "bomb",
|
||||
Body::Scarecrow => "scarecrow",
|
||||
Body::Cauldron => "cauldron",
|
||||
Body::ChestVines => "chest_vines",
|
||||
Body::Chest => "chest",
|
||||
Body::ChestDark => "chest_dark",
|
||||
Body::ChestDemon => "chest_demon",
|
||||
Body::ChestGold => "chest_gold",
|
||||
Body::ChestLight => "chest_light",
|
||||
Body::ChestOpen => "chest_open",
|
||||
Body::ChestSkull => "chest_skull",
|
||||
Body::Pumpkin => "pumpkin",
|
||||
Body::Pumpkin2 => "pumpkin_2",
|
||||
Body::Pumpkin3 => "pumpkin_3",
|
||||
Body::Pumpkin4 => "pumpkin_4",
|
||||
Body::Pumpkin5 => "pumpkin_5",
|
||||
Body::Campfire => "campfire",
|
||||
Body::CampfireLit => "campfire_lit",
|
||||
Body::LanternGround => "lantern_ground",
|
||||
Body::LanternGroundOpen => "lantern_ground_open",
|
||||
Body::LanternStanding => "lantern_standing",
|
||||
Body::LanternStanding2 => "lantern_standing_2",
|
||||
Body::PotionRed => "potion_red",
|
||||
Body::PotionBlue => "potion_blue",
|
||||
Body::PotionGreen => "potion_green",
|
||||
Body::Crate => "crate",
|
||||
Body::Tent => "tent",
|
||||
Body::WindowSpooky => "window_spooky",
|
||||
Body::DoorSpooky => "door_spooky",
|
||||
Body::Anvil => "anvil",
|
||||
Body::Gravestone => "gravestone",
|
||||
Body::Gravestone2 => "gravestone_2",
|
||||
Body::Bench => "bench",
|
||||
Body::Chair => "chair",
|
||||
Body::Chair2 => "chair_2",
|
||||
Body::Chair3 => "chair_3",
|
||||
Body::Table => "table",
|
||||
Body::Table2 => "table_2",
|
||||
Body::Table3 => "table_3",
|
||||
Body::Drawer => "drawer",
|
||||
Body::BedBlue => "bed_blue",
|
||||
Body::Carpet => "carpet",
|
||||
Body::Bedroll => "bedroll",
|
||||
Body::CarpetHumanRound => "carpet_human_round",
|
||||
Body::CarpetHumanSquare => "carpet_human_square",
|
||||
Body::CarpetHumanSquare2 => "carpet_human_square_2",
|
||||
Body::CarpetHumanSquircle => "carpet_human_squircle",
|
||||
Body::Pouch => "pouch",
|
||||
Body::CraftingBench => "crafting_bench",
|
||||
Body::BoltFire => "bolt_fire",
|
||||
Body::BoltFireBig => "bolt_fire_big",
|
||||
Body::ArrowSnake => "arrow_snake",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ fn get_handler(cmd: &ChatCommand) -> CommandHandler {
|
||||
ChatCommand::Waypoint => handle_waypoint,
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_give_item(
|
||||
server: &mut Server,
|
||||
client: EcsEntity,
|
||||
@ -616,85 +617,39 @@ fn handle_object(
|
||||
.with(ori);*/
|
||||
if let (Some(pos), Some(ori)) = (pos, ori) {
|
||||
let obj_str_res = obj_type.as_ref().map(String::as_str);
|
||||
let obj_type = match obj_str_res {
|
||||
Ok("scarecrow") => comp::object::Body::Scarecrow,
|
||||
Ok("cauldron") => comp::object::Body::Cauldron,
|
||||
Ok("chest_vines") => comp::object::Body::ChestVines,
|
||||
Ok("chest") => comp::object::Body::Chest,
|
||||
Ok("chest_dark") => comp::object::Body::ChestDark,
|
||||
Ok("chest_demon") => comp::object::Body::ChestDemon,
|
||||
Ok("chest_gold") => comp::object::Body::ChestGold,
|
||||
Ok("chest_light") => comp::object::Body::ChestLight,
|
||||
Ok("chest_open") => comp::object::Body::ChestOpen,
|
||||
Ok("chest_skull") => comp::object::Body::ChestSkull,
|
||||
Ok("pumpkin") => comp::object::Body::Pumpkin,
|
||||
Ok("pumpkin_2") => comp::object::Body::Pumpkin2,
|
||||
Ok("pumpkin_3") => comp::object::Body::Pumpkin3,
|
||||
Ok("pumpkin_4") => comp::object::Body::Pumpkin4,
|
||||
Ok("pumpkin_5") => comp::object::Body::Pumpkin5,
|
||||
Ok("campfire") => comp::object::Body::Campfire,
|
||||
Ok("campfire_lit") => comp::object::Body::CampfireLit,
|
||||
Ok("lantern_ground") => comp::object::Body::LanternGround,
|
||||
Ok("lantern_ground_open") => comp::object::Body::LanternGroundOpen,
|
||||
Ok("lantern_2") => comp::object::Body::LanternStanding2,
|
||||
Ok("lantern") => comp::object::Body::LanternStanding,
|
||||
Ok("potion_blue") => comp::object::Body::PotionBlue,
|
||||
Ok("potion_green") => comp::object::Body::PotionGreen,
|
||||
Ok("potion_red") => comp::object::Body::PotionRed,
|
||||
Ok("crate") => comp::object::Body::Crate,
|
||||
Ok("tent") => comp::object::Body::Tent,
|
||||
Ok("bomb") => comp::object::Body::Bomb,
|
||||
Ok("window_spooky") => comp::object::Body::WindowSpooky,
|
||||
Ok("door_spooky") => comp::object::Body::DoorSpooky,
|
||||
Ok("carpet") => comp::object::Body::Carpet,
|
||||
Ok("table_human") => comp::object::Body::Table,
|
||||
Ok("table_human_2") => comp::object::Body::Table2,
|
||||
Ok("table_human_3") => comp::object::Body::Table3,
|
||||
Ok("drawer") => comp::object::Body::Drawer,
|
||||
Ok("bed_human_blue") => comp::object::Body::BedBlue,
|
||||
Ok("anvil") => comp::object::Body::Anvil,
|
||||
Ok("gravestone") => comp::object::Body::Gravestone,
|
||||
Ok("gravestone_2") => comp::object::Body::Gravestone2,
|
||||
Ok("chair") => comp::object::Body::Chair,
|
||||
Ok("chair_2") => comp::object::Body::Chair2,
|
||||
Ok("chair_3") => comp::object::Body::Chair3,
|
||||
Ok("bench_human") => comp::object::Body::Bench,
|
||||
Ok("bedroll") => comp::object::Body::Bedroll,
|
||||
Ok("carpet_human_round") => comp::object::Body::CarpetHumanRound,
|
||||
Ok("carpet_human_square") => comp::object::Body::CarpetHumanSquare,
|
||||
Ok("carpet_human_square_2") => comp::object::Body::CarpetHumanSquare2,
|
||||
Ok("carpet_human_squircle") => comp::object::Body::CarpetHumanSquircle,
|
||||
Ok("crafting_bench") => comp::object::Body::CraftingBench,
|
||||
_ => {
|
||||
return server.notify_client(
|
||||
client,
|
||||
ServerMsg::private(String::from("Object not found!")),
|
||||
);
|
||||
},
|
||||
};
|
||||
server
|
||||
.state
|
||||
.create_object(pos, obj_type)
|
||||
.with(comp::Ori(
|
||||
// converts player orientation into a 90° rotation for the object by using the axis
|
||||
// with the highest value
|
||||
Dir::from_unnormalized(ori.0.map(|e| {
|
||||
if e.abs() == ori.0.map(|e| e.abs()).reduce_partial_max() {
|
||||
e
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}))
|
||||
.unwrap_or_default(),
|
||||
))
|
||||
.build();
|
||||
server.notify_client(
|
||||
client,
|
||||
ServerMsg::private(format!(
|
||||
"Spawned: {}",
|
||||
obj_str_res.unwrap_or("<Unknown object>")
|
||||
)),
|
||||
);
|
||||
if let Some(obj_type) = comp::object::ALL_OBJECTS
|
||||
.iter()
|
||||
.find(|o| Ok(o.to_string()) == obj_str_res)
|
||||
{
|
||||
server
|
||||
.state
|
||||
.create_object(pos, *obj_type)
|
||||
.with(comp::Ori(
|
||||
// converts player orientation into a 90° rotation for the object by using the
|
||||
// axis with the highest value
|
||||
Dir::from_unnormalized(ori.0.map(|e| {
|
||||
if e.abs() == ori.0.map(|e| e.abs()).reduce_partial_max() {
|
||||
e
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}))
|
||||
.unwrap_or_default(),
|
||||
))
|
||||
.build();
|
||||
server.notify_client(
|
||||
client,
|
||||
ServerMsg::private(format!(
|
||||
"Spawned: {}",
|
||||
obj_str_res.unwrap_or("<Unknown object>")
|
||||
)),
|
||||
);
|
||||
} else {
|
||||
return server.notify_client(
|
||||
client,
|
||||
ServerMsg::private(String::from("Object not found!")),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
server.notify_client(client, ServerMsg::private(format!("You have no position!")));
|
||||
}
|
||||
|
@ -29,8 +29,6 @@ widget_ids! {
|
||||
}
|
||||
|
||||
const MAX_MESSAGES: usize = 100;
|
||||
// Maximum completions shown at once
|
||||
const MAX_COMPLETIONS: usize = 10;
|
||||
|
||||
#[derive(WidgetCommon)]
|
||||
pub struct Chat<'a> {
|
||||
@ -456,21 +454,6 @@ fn do_tab_completion(cursor: usize, input: &str, word: &str) -> (String, usize)
|
||||
}
|
||||
}
|
||||
|
||||
fn cursor_index_to_offset(
|
||||
index: text::cursor::Index,
|
||||
text: &str,
|
||||
ui: &Ui,
|
||||
fonts: &ConrodVoxygenFonts,
|
||||
) -> Option<usize> {
|
||||
// Width and font must match that of the chat TextEdit
|
||||
let width = 460.0;
|
||||
let font = ui.fonts.get(fonts.opensans.conrod_id)?;
|
||||
let font_size = fonts.opensans.scale(15);
|
||||
let infos = text::line::infos(&text, &font, font_size).wrap_by_whitespace(width);
|
||||
|
||||
text::glyph::index_after_cursor(infos, index)
|
||||
}
|
||||
|
||||
fn cursor_offset_to_index(
|
||||
offset: usize,
|
||||
text: &str,
|
||||
|
Loading…
Reference in New Issue
Block a user