diff --git a/common/src/cmd.rs b/common/src/cmd.rs index 423a948b65..1e7f708e8c 100644 --- a/common/src/cmd.rs +++ b/common/src/cmd.rs @@ -316,7 +316,9 @@ pub enum ServerChatCommand { DebugColumn, DebugWays, DeleteLocation, + DestroyTethers, DisconnectAllPlayers, + Dismount, DropAll, Dummy, Explosion, @@ -345,6 +347,7 @@ pub enum ServerChatCommand { MakeSprite, MakeVolume, Motd, + Mount, Object, PermitBuild, Players, @@ -373,6 +376,7 @@ pub enum ServerChatCommand { Spawn, Sudo, Tell, + Tether, Time, TimeScale, Tp, @@ -895,6 +899,22 @@ impl ServerChatCommand { ServerChatCommand::RepairEquipment => { cmd(vec![], "Repairs all equipped items", Some(Admin)) }, + ServerChatCommand::Tether => cmd( + vec![EntityTarget(Required)], + "Tether another entity to yourself", + 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", + Some(Admin), + ), } } @@ -985,6 +1005,10 @@ impl ServerChatCommand { ServerChatCommand::Lightning => "lightning", ServerChatCommand::Scale => "scale", ServerChatCommand::RepairEquipment => "repair_equipment", + ServerChatCommand::Tether => "tether", + ServerChatCommand::DestroyTethers => "destroy_tethers", + ServerChatCommand::Mount => "mount", + ServerChatCommand::Dismount => "dismount", } } diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 50ce0ec47e..e5eed4ad67 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -208,6 +208,10 @@ fn do_command( ServerChatCommand::Lightning => handle_lightning, ServerChatCommand::Scale => handle_scale, ServerChatCommand::RepairEquipment => handle_repair_equipment, + ServerChatCommand::Tether => handle_tether, + ServerChatCommand::DestroyTethers => handle_destroy_tethers, + ServerChatCommand::Mount => handle_mount, + ServerChatCommand::Dismount => handle_dismount, }; handler(server, client, target, args, cmd) @@ -4539,3 +4543,114 @@ fn handle_repair_equipment( Err(Content::Plain(action.help_string())) } } + +fn handle_tether( + server: &mut Server, + _client: EcsEntity, + target: EcsEntity, + args: Vec, + action: &ServerChatCommand, +) -> CmdResult<()> { + if let Some(entity_target) = parse_cmd_args!(args, EntityTarget) { + let entity_target = get_entity_target(entity_target, server)?; + + let tether_leader = server.state.ecs().uid_from_entity(target); + let tether_follower = server.state.ecs().uid_from_entity(entity_target); + + if let (Some(leader), Some(follower)) = (tether_leader, tether_follower) { + let tether_length = tether_leader + .and_then(|uid| server.state.ecs().entity_from_uid(uid)) + .and_then(|e| server.state.read_component_cloned::(e)) + .map(|b| b.dimensions().y * 1.5 + 1.0) + .unwrap_or(6.0); + server + .state + .link(Tethered { + leader, + follower, + tether_length, + }) + .map_err(|_| "Failed to tether entities".into()) + } else { + Err("Tether members don't have Uids.".into()) + } + } else { + Err(Content::Plain(action.help_string())) + } +} + +fn handle_destroy_tethers( + server: &mut Server, + _client: EcsEntity, + target: EcsEntity, + _args: Vec, + _action: &ServerChatCommand, +) -> CmdResult<()> { + server + .state + .ecs() + .write_storage::>() + .remove(target); + server + .state + .ecs() + .write_storage::>() + .remove(target); + Ok(()) +} + +fn handle_mount( + server: &mut Server, + _client: EcsEntity, + target: EcsEntity, + args: Vec, + action: &ServerChatCommand, +) -> CmdResult<()> { + if let Some(entity_target) = parse_cmd_args!(args, EntityTarget) { + let entity_target = get_entity_target(entity_target, server)?; + + let rider = server.state.ecs().uid_from_entity(target); + let mount = server.state.ecs().uid_from_entity(entity_target); + + if let (Some(rider), Some(mount)) = (rider, mount) { + server + .state + .link(common::mounting::Mounting { mount, rider }) + .map_err(|_| "Failed to tether entities".into()) + } else { + Err("Mount and/or rider doesn't have an Uid component.".into()) + } + } else { + Err(Content::Plain(action.help_string())) + } +} + +fn handle_dismount( + server: &mut Server, + _client: EcsEntity, + target: EcsEntity, + _args: Vec, + _action: &ServerChatCommand, +) -> CmdResult<()> { + server + .state + .ecs() + .write_storage::>() + .remove(target); + server + .state + .ecs() + .write_storage::>() + .remove(target); + server + .state + .ecs() + .write_storage::>() + .remove(target); + server + .state + .ecs() + .write_storage::() + .remove(target); + Ok(()) +}