veloren/server/src/events/interaction.rs

206 lines
7.1 KiB
Rust
Raw Normal View History

use specs::{world::WorldExt, Entity as EcsEntity};
use tracing::error;
2020-02-16 20:04:06 +00:00
use common::{
comp::{self, inventory::slot::EquipSlot, item, slot::Slot, Inventory, Pos},
2020-10-31 02:34:44 +00:00
consts::MAX_MOUNT_RANGE,
uid::Uid,
2020-02-16 20:04:06 +00:00
};
use common_net::{msg::ServerGeneral, sync::WorldSyncExt};
use crate::{
client::Client,
presence::{Presence, RegionSubscription},
Server,
};
2020-02-16 20:04:06 +00:00
2020-10-07 02:23:20 +00:00
pub fn handle_lantern(server: &mut Server, entity: EcsEntity, enable: bool) {
let ecs = server.state_mut().ecs();
2020-10-07 02:23:20 +00:00
let lantern_exists = ecs
.read_storage::<comp::LightEmitter>()
.get(entity)
2020-10-07 02:23:20 +00:00
.map_or(false, |light| light.strength > 0.0);
if lantern_exists != enable {
if !enable {
server
.state_mut()
.ecs()
.write_storage::<comp::LightEmitter>()
2020-10-07 02:23:20 +00:00
.remove(entity);
} else {
let inventory_storage = ecs.read_storage::<Inventory>();
let lantern_opt = inventory_storage
2020-10-07 02:23:20 +00:00
.get(entity)
.and_then(|inventory| inventory.equipped(EquipSlot::Lantern))
2020-10-07 02:23:20 +00:00
.and_then(|item| {
if let comp::item::ItemKind::Lantern(l) = item.kind() {
Some(l)
} else {
None
}
});
2020-10-07 02:23:20 +00:00
if let Some(lantern) = lantern_opt {
let _ =
ecs.write_storage::<comp::LightEmitter>()
.insert(entity, comp::LightEmitter {
col: lantern.color(),
strength: lantern.strength(),
flicker: 0.35,
animated: true,
});
}
}
}
}
2020-02-16 20:04:06 +00:00
pub fn handle_mount(server: &mut Server, mounter: EcsEntity, mountee: EcsEntity) {
let state = server.state_mut();
if state
.ecs()
.read_storage::<comp::Mounting>()
.get(mounter)
.is_none()
{
2020-07-31 05:13:31 +00:00
let not_mounting_yet = matches!(
state.ecs().read_storage::<comp::MountState>().get(mountee),
Some(comp::MountState::Unmounted)
);
2020-02-16 20:04:06 +00:00
2020-10-31 02:34:44 +00:00
let within_range = within_mounting_range(
state.ecs().read_storage::<comp::Pos>().get(mounter),
state.ecs().read_storage::<comp::Pos>().get(mountee),
);
if not_mounting_yet && within_range {
2020-02-16 20:04:06 +00:00
if let (Some(mounter_uid), Some(mountee_uid)) = (
state.ecs().uid_from_entity(mounter),
state.ecs().uid_from_entity(mountee),
) {
2020-07-31 05:13:31 +00:00
state.write_component(mountee, comp::MountState::MountedBy(mounter_uid));
state.write_component(mounter, comp::Mounting(mountee_uid));
2020-02-16 20:04:06 +00:00
}
}
}
}
pub fn handle_unmount(server: &mut Server, mounter: EcsEntity) {
let state = server.state_mut();
let mountee_entity = state
.ecs()
.write_storage::<comp::Mounting>()
.get(mounter)
.and_then(|mountee| state.ecs().entity_from_uid(mountee.0.into()));
if let Some(mountee_entity) = mountee_entity {
state
.ecs()
.write_storage::<comp::MountState>()
.get_mut(mountee_entity)
.map(|mut ms| *ms = comp::MountState::Unmounted);
2020-02-16 20:04:06 +00:00
}
state.delete_component::<comp::Mounting>(mounter);
}
#[allow(clippy::nonminimal_bool)] // TODO: Pending review in #587
2020-02-16 20:04:06 +00:00
pub fn handle_possess(server: &Server, possessor_uid: Uid, possesse_uid: Uid) {
let ecs = &server.state.ecs();
2020-02-16 20:04:06 +00:00
if let (Some(possessor), Some(possesse)) = (
ecs.entity_from_uid(possessor_uid.into()),
ecs.entity_from_uid(possesse_uid.into()),
) {
// Check that entities still exist
if !(possessor.gen().is_alive() && ecs.is_alive(possessor))
|| !(possesse.gen().is_alive() && ecs.is_alive(possesse))
{
error!(
"Error possessing! either the possessor entity or possesse entity no longer exists"
);
return;
}
2020-02-16 20:04:06 +00:00
let mut clients = ecs.write_storage::<Client>();
if clients.get_mut(possesse).is_some() {
error!("can't possess other players");
return;
}
match (|| -> Option<Result<(), specs::error::Error>> {
let c = clients.remove(possessor)?;
clients.insert(possesse, c).ok()?;
//optional entities
let mut players = ecs.write_storage::<comp::Player>();
2020-11-04 10:46:17 +00:00
let mut presence = ecs.write_storage::<Presence>();
let mut subscriptions = ecs.write_storage::<RegionSubscription>();
let mut admins = ecs.write_storage::<comp::Admin>();
let mut waypoints = ecs.write_storage::<comp::Waypoint>();
players
.remove(possessor)
.map(|p| players.insert(possesse, p).ok()?);
2020-11-04 10:46:17 +00:00
presence
.remove(possessor)
.map(|p| presence.insert(possesse, p).ok()?);
subscriptions
.remove(possessor)
.map(|s| subscriptions.insert(possesse, s).ok()?);
admins
.remove(possessor)
.map(|a| admins.insert(possesse, a).ok()?);
waypoints
.remove(possessor)
.map(|w| waypoints.insert(possesse, w).ok()?);
Some(Ok(()))
})() {
Some(Ok(())) => (),
Some(Err(e)) => {
error!(?e, ?possesse, "Error inserting component during possession");
return;
},
None => {
error!(?possessor, "Error removing component during possession");
return;
},
2020-02-16 20:04:06 +00:00
}
clients
.get_mut(possesse)
.map(|c| c.send_fallible(ServerGeneral::SetPlayerEntity(possesse_uid)));
// Put possess item into loadout
let mut inventories = ecs.write_storage::<Inventory>();
let mut inventory = inventories
.entry(possesse)
.expect("Could not read inventory component while possessing")
.or_insert(Inventory::new_empty());
let debug_item = comp::Item::new_from_asset_expect("common.items.debug.possess");
if let item::ItemKind::Tool(_) = debug_item.kind() {
inventory
.swap(
Slot::Equip(EquipSlot::Mainhand),
Slot::Equip(EquipSlot::Offhand),
)
.unwrap_none(); // Swapping main and offhand never results in leftover items
inventory.replace_loadout_item(EquipSlot::Mainhand, Some(debug_item));
}
// Remove will of the entity
ecs.write_storage::<comp::Agent>().remove(possesse);
// Reset controller of former shell
ecs.write_storage::<comp::Controller>()
.get_mut(possessor)
.map(|c| c.reset());
2020-02-16 20:04:06 +00:00
}
}
2020-10-31 02:34:44 +00:00
fn within_mounting_range(player_position: Option<&Pos>, mount_position: Option<&Pos>) -> bool {
match (player_position, mount_position) {
(Some(ppos), Some(ipos)) => ppos.0.distance_squared(ipos.0) < MAX_MOUNT_RANGE.powi(2),
_ => false,
}
}