mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
transform server event
This commit is contained in:
parent
c1115dfe97
commit
b9a3fa1edc
@ -9,6 +9,7 @@ use crate::{
|
|||||||
misc::PortalData,
|
misc::PortalData,
|
||||||
DisconnectReason, LootOwner, Ori, Pos, UnresolvedChatMsg, Vel,
|
DisconnectReason, LootOwner, Ori, Pos, UnresolvedChatMsg, Vel,
|
||||||
},
|
},
|
||||||
|
generation::EntityInfo,
|
||||||
lottery::LootSpec,
|
lottery::LootSpec,
|
||||||
mounting::VolumePos,
|
mounting::VolumePos,
|
||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
@ -260,6 +261,8 @@ pub struct SetPetStayEvent(pub EcsEntity, pub EcsEntity, pub bool);
|
|||||||
|
|
||||||
pub struct PossessEvent(pub Uid, pub Uid);
|
pub struct PossessEvent(pub Uid, pub Uid);
|
||||||
|
|
||||||
|
pub struct TransformEvent(pub Uid, pub EntityInfo);
|
||||||
|
|
||||||
pub struct InitializeCharacterEvent {
|
pub struct InitializeCharacterEvent {
|
||||||
pub entity: EcsEntity,
|
pub entity: EcsEntity,
|
||||||
pub character_id: CharacterId,
|
pub character_id: CharacterId,
|
||||||
@ -531,6 +534,7 @@ pub fn register_event_busses(ecs: &mut World) {
|
|||||||
ecs.insert(EventBus::<TeleportToPositionEvent>::default());
|
ecs.insert(EventBus::<TeleportToPositionEvent>::default());
|
||||||
ecs.insert(EventBus::<StartTeleportingEvent>::default());
|
ecs.insert(EventBus::<StartTeleportingEvent>::default());
|
||||||
ecs.insert(EventBus::<ToggleSpriteLightEvent>::default());
|
ecs.insert(EventBus::<ToggleSpriteLightEvent>::default());
|
||||||
|
ecs.insert(EventBus::<TransformEvent>::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Define ecs read data for event busses. And a way to convert them all to
|
/// Define ecs read data for event busses. And a way to convert them all to
|
||||||
|
@ -35,8 +35,7 @@ use common::{
|
|||||||
},
|
},
|
||||||
invite::InviteKind,
|
invite::InviteKind,
|
||||||
misc::PortalData,
|
misc::PortalData,
|
||||||
AdminRole, ChatType, Content, Inventory, Item, LightEmitter, Presence, PresenceKind,
|
AdminRole, ChatType, Content, Inventory, Item, LightEmitter, WaypointArea,
|
||||||
WaypointArea,
|
|
||||||
},
|
},
|
||||||
depot,
|
depot,
|
||||||
effect::Effect,
|
effect::Effect,
|
||||||
@ -54,7 +53,7 @@ use common::{
|
|||||||
rtsim::{Actor, Role},
|
rtsim::{Actor, Role},
|
||||||
terrain::{Block, BlockKind, CoordinateConversions, SpriteKind, TerrainChunkSize},
|
terrain::{Block, BlockKind, CoordinateConversions, SpriteKind, TerrainChunkSize},
|
||||||
tether::Tethered,
|
tether::Tethered,
|
||||||
uid::{IdMaps, Uid},
|
uid::Uid,
|
||||||
vol::ReadVol,
|
vol::ReadVol,
|
||||||
weather, Damage, DamageKind, DamageSource, Explosion, LoadoutBuilder, RadiusEffect,
|
weather, Damage, DamageKind, DamageSource, Explosion, LoadoutBuilder, RadiusEffect,
|
||||||
};
|
};
|
||||||
@ -628,6 +627,8 @@ fn handle_into_npc(
|
|||||||
args: Vec<String>,
|
args: Vec<String>,
|
||||||
action: &ServerChatCommand,
|
action: &ServerChatCommand,
|
||||||
) -> CmdResult<()> {
|
) -> CmdResult<()> {
|
||||||
|
use crate::events::shared::{transform_entity, TransformEntityError};
|
||||||
|
|
||||||
if client != target {
|
if client != target {
|
||||||
server.notify_client(
|
server.notify_client(
|
||||||
client,
|
client,
|
||||||
@ -661,69 +662,18 @@ fn handle_into_npc(
|
|||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
match NpcData::from_entity_info(entity_info) {
|
transform_entity(server, target, entity_info).map_err(|error| match error {
|
||||||
NpcData::Data {
|
TransformEntityError::EntityDead => {
|
||||||
inventory,
|
Content::localized_with_args("command-entity-dead", [("entity", "target")])
|
||||||
stats,
|
|
||||||
skill_set,
|
|
||||||
poise,
|
|
||||||
health,
|
|
||||||
body,
|
|
||||||
scale,
|
|
||||||
// changing alignments is cool idea, but needs more work
|
|
||||||
alignment: _,
|
|
||||||
// we aren't interested in these (yet?)
|
|
||||||
pos: _,
|
|
||||||
agent: _,
|
|
||||||
loot: _,
|
|
||||||
} => {
|
|
||||||
// Should do basically what StateExt::create_npc does
|
|
||||||
insert_or_replace_component(server, target, inventory, "player")?;
|
|
||||||
insert_or_replace_component(server, target, stats, "player")?;
|
|
||||||
insert_or_replace_component(server, target, skill_set, "player")?;
|
|
||||||
insert_or_replace_component(server, target, poise, "player")?;
|
|
||||||
if let Some(health) = health {
|
|
||||||
insert_or_replace_component(server, target, health, "player")?;
|
|
||||||
}
|
|
||||||
insert_or_replace_component(server, target, body, "player")?;
|
|
||||||
insert_or_replace_component(server, target, body.mass(), "player")?;
|
|
||||||
insert_or_replace_component(server, target, body.density(), "player")?;
|
|
||||||
insert_or_replace_component(server, target, body.collider(), "player")?;
|
|
||||||
insert_or_replace_component(server, target, scale, "player")?;
|
|
||||||
},
|
},
|
||||||
NpcData::Waypoint(_) => {
|
TransformEntityError::UnexpectedNpcWaypoint => {
|
||||||
return Err(Content::localized("command-unimplemented-waypoint-spawn"));
|
Content::localized("command-unimplemented-waypoint-spawn")
|
||||||
},
|
},
|
||||||
NpcData::Teleporter(_, _) => {
|
TransformEntityError::UnexpectedNpcTeleporter => {
|
||||||
return Err(Content::localized("command-unimplemented-teleporter-spawn"));
|
Content::localized("command-unimplemented-teleporter-spawn")
|
||||||
},
|
},
|
||||||
}
|
})?;
|
||||||
|
|
||||||
// Black magic
|
|
||||||
//
|
|
||||||
// Mainly needed to disable persistence
|
|
||||||
{
|
|
||||||
// TODO: let Imbris work out some edge-cases:
|
|
||||||
// - error on PresenseKind::LoadingCharacter
|
|
||||||
// - handle active inventory actions
|
|
||||||
let ecs = server.state.ecs();
|
|
||||||
let mut presences = ecs.write_storage::<Presence>();
|
|
||||||
let presence = presences.get_mut(target);
|
|
||||||
|
|
||||||
if let Some(presence) = presence
|
|
||||||
&& let PresenceKind::Character(id) = presence.kind
|
|
||||||
{
|
|
||||||
server.state.ecs().write_resource::<IdMaps>().remove_entity(
|
|
||||||
Some(target),
|
|
||||||
None,
|
|
||||||
Some(id),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
presence.kind = PresenceKind::Possessor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// End of black magic
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use crate::{
|
|||||||
error,
|
error,
|
||||||
rtsim::RtSim,
|
rtsim::RtSim,
|
||||||
state_ext::StateExt,
|
state_ext::StateExt,
|
||||||
sys::terrain::SAFE_ZONE_RADIUS,
|
sys::terrain::{NpcData, SAFE_ZONE_RADIUS},
|
||||||
Server, Settings, SpawnPoint,
|
Server, Settings, SpawnPoint,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
@ -31,9 +31,11 @@ use common::{
|
|||||||
DestroyEvent, EmitExt, Emitter, EnergyChangeEvent, EntityAttackedHookEvent, EventBus,
|
DestroyEvent, EmitExt, Emitter, EnergyChangeEvent, EntityAttackedHookEvent, EventBus,
|
||||||
ExplosionEvent, HealthChangeEvent, KnockbackEvent, LandOnGroundEvent, MakeAdminEvent,
|
ExplosionEvent, HealthChangeEvent, KnockbackEvent, LandOnGroundEvent, MakeAdminEvent,
|
||||||
ParryHookEvent, PoiseChangeEvent, RemoveLightEmitterEvent, RespawnEvent, SoundEvent,
|
ParryHookEvent, PoiseChangeEvent, RemoveLightEmitterEvent, RespawnEvent, SoundEvent,
|
||||||
StartTeleportingEvent, TeleportToEvent, TeleportToPositionEvent, UpdateMapMarkerEvent,
|
StartTeleportingEvent, TeleportToEvent, TeleportToPositionEvent, TransformEvent,
|
||||||
|
UpdateMapMarkerEvent,
|
||||||
},
|
},
|
||||||
event_emitters,
|
event_emitters,
|
||||||
|
generation::EntityInfo,
|
||||||
link::Is,
|
link::Is,
|
||||||
lottery::distribute_many,
|
lottery::distribute_many,
|
||||||
mounting::{Rider, VolumeRider},
|
mounting::{Rider, VolumeRider},
|
||||||
@ -49,13 +51,13 @@ use common::{
|
|||||||
vol::ReadVol,
|
vol::ReadVol,
|
||||||
CachedSpatialGrid, Damage, DamageKind, DamageSource, GroupTarget, RadiusEffect,
|
CachedSpatialGrid, Damage, DamageKind, DamageSource, GroupTarget, RadiusEffect,
|
||||||
};
|
};
|
||||||
use common_net::msg::ServerGeneral;
|
use common_net::{msg::ServerGeneral, sync::WorldSyncExt};
|
||||||
use common_state::{AreasContainer, BlockChange, NoDurabilityArea};
|
use common_state::{AreasContainer, BlockChange, NoDurabilityArea};
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use specs::{
|
use specs::{
|
||||||
shred, DispatcherBuilder, Entities, Entity as EcsEntity, Entity, Join, LendJoin, Read,
|
shred, DispatcherBuilder, Entities, Entity as EcsEntity, Entity, Join, LendJoin, Read,
|
||||||
ReadExpect, ReadStorage, SystemData, Write, WriteExpect, WriteStorage,
|
ReadExpect, ReadStorage, SystemData, WorldExt, Write, WriteExpect, WriteStorage,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, iter, sync::Arc, time::Duration};
|
use std::{collections::HashMap, iter, sync::Arc, time::Duration};
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
@ -2098,3 +2100,114 @@ impl ServerEvent for StartTeleportingEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn handle_transform(server: &mut Server, TransformEvent(uid, info): TransformEvent) {
|
||||||
|
let Some(entity) = server.state().ecs().entity_from_uid(uid) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = transform_entity(server, entity, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum TransformEntityError {
|
||||||
|
EntityDead,
|
||||||
|
UnexpectedNpcWaypoint,
|
||||||
|
UnexpectedNpcTeleporter,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_entity(
|
||||||
|
server: &mut Server,
|
||||||
|
entity: Entity,
|
||||||
|
info: EntityInfo,
|
||||||
|
) -> Result<(), TransformEntityError> {
|
||||||
|
let is_player = server
|
||||||
|
.state()
|
||||||
|
.read_storage::<comp::Player>()
|
||||||
|
.contains(entity);
|
||||||
|
|
||||||
|
match NpcData::from_entity_info(info) {
|
||||||
|
NpcData::Data {
|
||||||
|
inventory,
|
||||||
|
stats,
|
||||||
|
skill_set,
|
||||||
|
poise,
|
||||||
|
health,
|
||||||
|
body,
|
||||||
|
scale,
|
||||||
|
agent,
|
||||||
|
loot,
|
||||||
|
alignment: _,
|
||||||
|
pos: _,
|
||||||
|
} => {
|
||||||
|
fn set_or_remove_component<C: specs::Component>(
|
||||||
|
server: &mut Server,
|
||||||
|
entity: EcsEntity,
|
||||||
|
component: Option<C>,
|
||||||
|
) -> Result<(), TransformEntityError> {
|
||||||
|
let mut storage = server.state.ecs_mut().write_storage::<C>();
|
||||||
|
|
||||||
|
if let Some(component) = component {
|
||||||
|
storage
|
||||||
|
.insert(entity, component)
|
||||||
|
.and(Ok(()))
|
||||||
|
.map_err(|_| TransformEntityError::EntityDead)
|
||||||
|
} else {
|
||||||
|
storage.remove(entity);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable persistence
|
||||||
|
{
|
||||||
|
// Run persistence once before disabling it
|
||||||
|
super::player::persist_entity(server.state_mut(), entity);
|
||||||
|
|
||||||
|
// TODO: let Imbris work out some edge-cases:
|
||||||
|
// - error on PresenseKind::LoadingCharacter
|
||||||
|
// - handle active inventory actions
|
||||||
|
let ecs = server.state.ecs();
|
||||||
|
let mut presences = ecs.write_storage::<Presence>();
|
||||||
|
let presence = presences.get_mut(entity);
|
||||||
|
|
||||||
|
if let Some(presence) = presence
|
||||||
|
&& let PresenceKind::Character(id) = presence.kind
|
||||||
|
{
|
||||||
|
server.state.ecs().write_resource::<IdMaps>().remove_entity(
|
||||||
|
Some(entity),
|
||||||
|
None,
|
||||||
|
Some(id),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
presence.kind = PresenceKind::Possessor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should do basically what StateExt::create_npc does
|
||||||
|
set_or_remove_component(server, entity, Some(inventory))?;
|
||||||
|
set_or_remove_component(server, entity, Some(stats))?;
|
||||||
|
set_or_remove_component(server, entity, Some(skill_set))?;
|
||||||
|
set_or_remove_component(server, entity, Some(poise))?;
|
||||||
|
set_or_remove_component(server, entity, health)?;
|
||||||
|
set_or_remove_component(server, entity, Some(body))?;
|
||||||
|
set_or_remove_component(server, entity, Some(body.mass()))?;
|
||||||
|
set_or_remove_component(server, entity, Some(body.density()))?;
|
||||||
|
set_or_remove_component(server, entity, Some(body.collider()))?;
|
||||||
|
set_or_remove_component(server, entity, Some(scale))?;
|
||||||
|
|
||||||
|
// Don't add Agent or ItemDrops to players
|
||||||
|
if !is_player {
|
||||||
|
set_or_remove_component(server, entity, agent)?;
|
||||||
|
set_or_remove_component(server, entity, loot.to_items().map(comp::ItemDrops))?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
NpcData::Waypoint(_) => {
|
||||||
|
return Err(TransformEntityError::UnexpectedNpcWaypoint);
|
||||||
|
},
|
||||||
|
NpcData::Teleporter(_, _) => {
|
||||||
|
return Err(TransformEntityError::UnexpectedNpcTeleporter);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -11,16 +11,13 @@ use specs::{
|
|||||||
WriteExpect,
|
WriteExpect,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use group_manip::update_map_markers;
|
|
||||||
pub(crate) use trade::cancel_trades_for;
|
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
entity_creation::{
|
entity_creation::{
|
||||||
handle_create_item_drop, handle_create_npc, handle_create_object, handle_create_ship,
|
handle_create_item_drop, handle_create_npc, handle_create_object, handle_create_ship,
|
||||||
handle_create_teleporter, handle_create_waypoint, handle_initialize_character,
|
handle_create_teleporter, handle_create_waypoint, handle_initialize_character,
|
||||||
handle_initialize_spectator, handle_loaded_character_data, handle_shockwave, handle_shoot,
|
handle_initialize_spectator, handle_loaded_character_data, handle_shockwave, handle_shoot,
|
||||||
},
|
},
|
||||||
entity_manipulation::handle_delete,
|
entity_manipulation::{handle_delete, handle_transform},
|
||||||
interaction::handle_tame_pet,
|
interaction::handle_tame_pet,
|
||||||
mounting::{handle_mount, handle_mount_volume, handle_unmount},
|
mounting::{handle_mount, handle_mount_volume, handle_unmount},
|
||||||
player::{
|
player::{
|
||||||
@ -40,6 +37,14 @@ mod mounting;
|
|||||||
mod player;
|
mod player;
|
||||||
mod trade;
|
mod trade;
|
||||||
|
|
||||||
|
pub(crate) mod shared {
|
||||||
|
pub(crate) use super::{
|
||||||
|
entity_manipulation::{transform_entity, TransformEntityError},
|
||||||
|
group_manip::update_map_markers,
|
||||||
|
trade::cancel_trades_for,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ServerEvent: Send + Sync + 'static {
|
pub trait ServerEvent: Send + Sync + 'static {
|
||||||
type SystemData<'a>: specs::SystemData<'a>;
|
type SystemData<'a>: specs::SystemData<'a>;
|
||||||
|
|
||||||
@ -165,6 +170,7 @@ impl Server {
|
|||||||
));
|
));
|
||||||
});
|
});
|
||||||
self.handle_serial_events(handle_possess);
|
self.handle_serial_events(handle_possess);
|
||||||
|
self.handle_serial_events(handle_transform);
|
||||||
self.handle_serial_events(|this, ev: CommandEvent| {
|
self.handle_serial_events(|this, ev: CommandEvent| {
|
||||||
this.process_command(ev.0, ev.1, ev.2);
|
this.process_command(ev.0, ev.1, ev.2);
|
||||||
});
|
});
|
||||||
|
@ -65,7 +65,7 @@ pub fn handle_exit_ingame(server: &mut Server, entity: EcsEntity, skip_persisten
|
|||||||
|
|
||||||
// Cancel trades here since we don't use `delete_entity_recorded` and we
|
// Cancel trades here since we don't use `delete_entity_recorded` and we
|
||||||
// remove `Uid` below.
|
// remove `Uid` below.
|
||||||
super::cancel_trades_for(state, entity);
|
super::trade::cancel_trades_for(state, entity);
|
||||||
|
|
||||||
let maybe_group = state.read_component_copied::<group::Group>(entity);
|
let maybe_group = state.read_component_copied::<group::Group>(entity);
|
||||||
let maybe_admin = state.delete_component::<comp::Admin>(entity);
|
let maybe_admin = state.delete_component::<comp::Admin>(entity);
|
||||||
@ -248,7 +248,7 @@ pub fn handle_client_disconnect(
|
|||||||
// temporarily unable to log in during this period to avoid
|
// temporarily unable to log in during this period to avoid
|
||||||
// the race condition of their login fetching their old data
|
// the race condition of their login fetching their old data
|
||||||
// and overwriting the data saved here.
|
// and overwriting the data saved here.
|
||||||
fn persist_entity(state: &mut State, entity: EcsEntity) -> EcsEntity {
|
pub(super) fn persist_entity(state: &mut State, entity: EcsEntity) -> EcsEntity {
|
||||||
if let (
|
if let (
|
||||||
Some(presence),
|
Some(presence),
|
||||||
Some(skill_set),
|
Some(skill_set),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{client::Client, events::update_map_markers};
|
use crate::{client::Client, events::shared::update_map_markers};
|
||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
self, anchor::Anchor, group::GroupManager, Agent, Alignment, Behavior, BehaviorCapability,
|
self, anchor::Anchor, group::GroupManager, Agent, Alignment, Behavior, BehaviorCapability,
|
||||||
|
@ -2,7 +2,7 @@ use crate::{
|
|||||||
automod::AutoMod,
|
automod::AutoMod,
|
||||||
chat::ChatExporter,
|
chat::ChatExporter,
|
||||||
client::Client,
|
client::Client,
|
||||||
events::{self, update_map_markers},
|
events::{self, shared::update_map_markers},
|
||||||
persistence::PersistedComponents,
|
persistence::PersistedComponents,
|
||||||
pet::restore_pet,
|
pet::restore_pet,
|
||||||
presence::RepositionOnChunkLoad,
|
presence::RepositionOnChunkLoad,
|
||||||
@ -1212,7 +1212,7 @@ impl StateExt for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cancel extant trades
|
// Cancel extant trades
|
||||||
events::cancel_trades_for(self, entity);
|
events::shared::cancel_trades_for(self, entity);
|
||||||
|
|
||||||
// NOTE: We expect that these 3 components are never removed from an entity (nor
|
// NOTE: We expect that these 3 components are never removed from an entity (nor
|
||||||
// mutated) (at least not without updating the relevant mappings)!
|
// mutated) (at least not without updating the relevant mappings)!
|
||||||
|
Loading…
Reference in New Issue
Block a user