2021-03-21 16:09:16 +00:00
|
|
|
use specs::{world::WorldExt, Builder, Entity as EcsEntity};
|
2021-01-08 19:12:09 +00:00
|
|
|
use tracing::error;
|
2021-03-21 16:09:16 +00:00
|
|
|
use vek::*;
|
2021-01-08 19:12:09 +00:00
|
|
|
|
2020-02-16 20:04:06 +00:00
|
|
|
use common::{
|
2021-03-21 17:45:01 +00:00
|
|
|
comp::{
|
|
|
|
self, agent::AgentEvent, inventory::slot::EquipSlot, item, slot::Slot, tool::ToolKind,
|
|
|
|
Inventory, Pos,
|
|
|
|
},
|
2020-10-31 02:34:44 +00:00
|
|
|
consts::MAX_MOUNT_RANGE,
|
2021-03-21 20:09:59 +00:00
|
|
|
outcome::Outcome,
|
2020-12-13 17:11:55 +00:00
|
|
|
uid::Uid,
|
2021-03-21 16:09:16 +00:00
|
|
|
vol::ReadVol,
|
2020-02-16 20:04:06 +00:00
|
|
|
};
|
2020-12-13 17:11:55 +00:00
|
|
|
use common_net::{msg::ServerGeneral, sync::WorldSyncExt};
|
2021-01-08 19:12:09 +00:00
|
|
|
|
|
|
|
use crate::{
|
|
|
|
client::Client,
|
|
|
|
presence::{Presence, RegionSubscription},
|
2021-02-17 02:15:45 +00:00
|
|
|
state_ext::StateExt,
|
2021-01-08 19:12:09 +00:00
|
|
|
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) {
|
2020-05-04 15:15:31 +00:00
|
|
|
let ecs = server.state_mut().ecs();
|
2020-10-07 02:23:20 +00:00
|
|
|
|
|
|
|
let lantern_exists = ecs
|
2020-05-04 15:15:31 +00:00
|
|
|
.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()
|
2020-05-04 15:15:31 +00:00
|
|
|
.write_storage::<comp::LightEmitter>()
|
2020-10-07 02:23:20 +00:00
|
|
|
.remove(entity);
|
|
|
|
} else {
|
2021-01-08 19:12:09 +00:00
|
|
|
let inventory_storage = ecs.read_storage::<Inventory>();
|
|
|
|
let lantern_opt = inventory_storage
|
2020-10-07 02:23:20 +00:00
|
|
|
.get(entity)
|
2021-01-08 19:12:09 +00:00
|
|
|
.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-05-04 15:15:31 +00:00
|
|
|
});
|
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-05-04 15:15:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-31 20:29:50 +00:00
|
|
|
pub fn handle_npc_interaction(server: &mut Server, interactor: EcsEntity, npc_entity: EcsEntity) {
|
|
|
|
let state = server.state_mut();
|
|
|
|
if let Some(agent) = state
|
|
|
|
.ecs()
|
|
|
|
.write_storage::<comp::Agent>()
|
|
|
|
.get_mut(npc_entity)
|
|
|
|
{
|
|
|
|
if let Some(interactor_uid) = state.ecs().uid_from_entity(interactor) {
|
|
|
|
agent.inbox.push_front(AgentEvent::Talk(interactor_uid));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
|
2021-01-07 20:25:12 +00:00
|
|
|
.map(|mut ms| *ms = comp::MountState::Unmounted);
|
2020-02-16 20:04:06 +00:00
|
|
|
}
|
|
|
|
state.delete_component::<comp::Mounting>(mounter);
|
|
|
|
}
|
|
|
|
|
2020-06-10 19:47:36 +00:00
|
|
|
#[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) {
|
2020-11-12 05:00:17 +00:00
|
|
|
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()),
|
|
|
|
) {
|
2020-04-01 15:04:04 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2021-02-17 02:15:45 +00:00
|
|
|
if ecs.read_storage::<Client>().get(possesse).is_some() {
|
2020-10-21 10:23:34 +00:00
|
|
|
error!("can't possess other players");
|
|
|
|
return;
|
|
|
|
}
|
2020-03-17 13:15:39 +00:00
|
|
|
|
2020-10-21 10:23:34 +00:00
|
|
|
match (|| -> Option<Result<(), specs::error::Error>> {
|
2021-02-17 02:15:45 +00:00
|
|
|
let mut clients = ecs.write_storage::<Client>();
|
2020-10-21 10:23:34 +00:00
|
|
|
let c = clients.remove(possessor)?;
|
|
|
|
clients.insert(possesse, c).ok()?;
|
2021-02-17 02:15:45 +00:00
|
|
|
let playerlist_messages = if let Some(client) = clients.get(possesse) {
|
|
|
|
client.send_fallible(ServerGeneral::SetPlayerEntity(possesse_uid));
|
|
|
|
// If a player is posessing non player, add possesse to playerlist as player and
|
|
|
|
// remove old player
|
|
|
|
if let Some(possessor_player) = ecs.read_storage::<comp::Player>().get(possessor) {
|
|
|
|
let admins = ecs.read_storage::<comp::Admin>();
|
|
|
|
let entity_possession_msg = ServerGeneral::PlayerListUpdate(
|
|
|
|
common_net::msg::server::PlayerListUpdate::Add(
|
|
|
|
possesse_uid,
|
|
|
|
common_net::msg::server::PlayerInfo {
|
|
|
|
player_alias: possessor_player.alias.clone(),
|
|
|
|
is_online: true,
|
|
|
|
is_admin: admins.get(possessor).is_some(),
|
|
|
|
character: ecs.read_storage::<comp::Stats>().get(possesse).map(
|
|
|
|
|s| common_net::msg::CharacterInfo {
|
|
|
|
name: s.name.clone(),
|
|
|
|
},
|
|
|
|
),
|
|
|
|
},
|
|
|
|
),
|
|
|
|
);
|
|
|
|
let remove_old_player_msg = ServerGeneral::PlayerListUpdate(
|
|
|
|
common_net::msg::server::PlayerListUpdate::Remove(possessor_uid),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Send msg to new possesse client now because it is not yet considered a player
|
|
|
|
// and will be missed by notify_players
|
|
|
|
client.send_fallible(entity_possession_msg.clone());
|
|
|
|
client.send_fallible(remove_old_player_msg.clone());
|
|
|
|
Some((remove_old_player_msg, entity_possession_msg))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
drop(clients);
|
|
|
|
if let Some((remove_player, possess_entity)) = playerlist_messages {
|
|
|
|
server.state().notify_players(possess_entity);
|
|
|
|
server.state().notify_players(remove_player);
|
|
|
|
}
|
2020-10-21 10:23:34 +00:00
|
|
|
//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>();
|
2020-10-21 10:23:34 +00:00
|
|
|
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()?);
|
2020-10-21 10:23:34 +00:00
|
|
|
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
|
|
|
}
|
2020-10-21 10:23:34 +00:00
|
|
|
|
|
|
|
// Put possess item into loadout
|
2021-01-08 19:12:09 +00:00
|
|
|
let mut inventories = ecs.write_storage::<Inventory>();
|
|
|
|
let mut inventory = inventories
|
2020-10-21 10:23:34 +00:00
|
|
|
.entry(possesse)
|
2021-01-08 19:12:09 +00:00
|
|
|
.expect("Could not read inventory component while possessing")
|
|
|
|
.or_insert(Inventory::new_empty());
|
|
|
|
|
2021-02-19 23:45:48 +00:00
|
|
|
let debug_item = comp::Item::new_from_asset_expect("common.items.debug.admin_stick");
|
2021-01-08 19:12:09 +00:00
|
|
|
if let item::ItemKind::Tool(_) = debug_item.kind() {
|
|
|
|
inventory
|
|
|
|
.swap(
|
|
|
|
Slot::Equip(EquipSlot::Mainhand),
|
|
|
|
Slot::Equip(EquipSlot::Offhand),
|
|
|
|
)
|
2021-01-09 18:10:12 +00:00
|
|
|
.first()
|
2021-01-08 19:12:09 +00:00
|
|
|
.unwrap_none(); // Swapping main and offhand never results in leftover items
|
|
|
|
|
|
|
|
inventory.replace_loadout_item(EquipSlot::Mainhand, Some(debug_item));
|
2020-10-21 10:23:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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,
|
|
|
|
}
|
|
|
|
}
|
2021-03-21 16:09:16 +00:00
|
|
|
|
2021-03-21 17:45:01 +00:00
|
|
|
pub fn handle_mine_block(server: &mut Server, pos: Vec3<i32>, tool: Option<ToolKind>) {
|
2021-03-21 16:09:16 +00:00
|
|
|
let state = server.state_mut();
|
|
|
|
if state.can_set_block(pos) {
|
|
|
|
let block = state.terrain().get(pos).ok().copied();
|
2021-03-21 20:38:08 +00:00
|
|
|
if let Some(block) = block.filter(|b| b.mine_tool().map_or(false, |t| Some(t) == tool)) {
|
2021-03-21 20:09:59 +00:00
|
|
|
// Drop item if one is recoverable from the block
|
2021-03-21 16:09:16 +00:00
|
|
|
if let Some(item) = comp::Item::try_reclaim_from_block(block) {
|
|
|
|
state
|
|
|
|
.create_object(Default::default(), comp::object::Body::Pouch)
|
|
|
|
.with(comp::Pos(pos.map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0)))
|
|
|
|
.with(item)
|
|
|
|
.build();
|
|
|
|
}
|
|
|
|
|
|
|
|
state.set_block(pos, block.into_vacant());
|
2021-03-21 20:09:59 +00:00
|
|
|
state
|
|
|
|
.ecs()
|
|
|
|
.write_resource::<Vec<Outcome>>()
|
|
|
|
.push(Outcome::BreakBlock {
|
|
|
|
pos,
|
|
|
|
color: block.get_color(),
|
|
|
|
});
|
2021-03-21 16:09:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|