mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'imbris/misc_fix' into 'master'
Trade canceling related tweaks, make kill_npcs not leave clutter (and actually remove entities in the first place), and misc tweaks See merge request veloren/veloren!3555
This commit is contained in:
commit
275b17be57
@ -17,11 +17,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Use fluent for translations
|
- Use fluent for translations
|
||||||
- First tab on Login screen triggers username focus
|
- First tab on Login screen triggers username focus
|
||||||
- Certain NPCs will now attack when alone with victim
|
- Certain NPCs will now attack when alone with victim
|
||||||
|
- /kill_npcs no longer leaves drops behind and also has bug causing it to not destroy entities
|
||||||
|
fixed.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixed crash due to zooming out very far
|
- Fixed crash due to zooming out very far
|
||||||
|
- Client properly knows trade was cancelled when exiting to the character screen (and no longer
|
||||||
|
tries to display the trade window when rejoining)
|
||||||
|
- Cancel trades for an entity when it is deleted (note this doesn't effect trades between players
|
||||||
|
since their entities are not removed).
|
||||||
|
|
||||||
## [0.13.0] - 2022-07-23
|
## [0.13.0] - 2022-07-23
|
||||||
|
|
||||||
|
@ -2065,6 +2065,8 @@ impl Client {
|
|||||||
PresenceKind::Possessor => PresenceKind::Possessor,
|
PresenceKind::Possessor => PresenceKind::Possessor,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Clear pending trade
|
||||||
|
self.pending_trade = None;
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::Other("Failed to find entity from uid.".into()));
|
return Err(Error::Other("Failed to find entity from uid.".into()));
|
||||||
}
|
}
|
||||||
@ -2543,6 +2545,9 @@ impl Client {
|
|||||||
|
|
||||||
/// Clean client ECS state
|
/// Clean client ECS state
|
||||||
fn clean_state(&mut self) {
|
fn clean_state(&mut self) {
|
||||||
|
// Clear pending trade
|
||||||
|
self.pending_trade = None;
|
||||||
|
|
||||||
let client_uid = self
|
let client_uid = self
|
||||||
.uid()
|
.uid()
|
||||||
.map(|u| u.into())
|
.map(|u| u.into())
|
||||||
|
@ -195,10 +195,7 @@ impl Health {
|
|||||||
|
|
||||||
pub fn should_die(&self) -> bool { self.current == 0 }
|
pub fn should_die(&self) -> bool { self.current == 0 }
|
||||||
|
|
||||||
pub fn kill(&mut self) {
|
pub fn kill(&mut self) { self.current = 0; }
|
||||||
self.current = 0;
|
|
||||||
self.is_dead = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn revive(&mut self) {
|
pub fn revive(&mut self) {
|
||||||
|
@ -140,6 +140,7 @@ impl Client {
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Like `send` but any errors are explicitly ignored.
|
||||||
pub(crate) fn send_fallible<M: Into<ServerMsg>>(&self, msg: M) { let _ = self.send(msg); }
|
pub(crate) fn send_fallible<M: Into<ServerMsg>>(&self, msg: M) { let _ = self.send(msg); }
|
||||||
|
|
||||||
pub(crate) fn send_prepared(&self, msg: &PreparedMsg) -> Result<(), StreamError> {
|
pub(crate) fn send_prepared(&self, msg: &PreparedMsg) -> Result<(), StreamError> {
|
||||||
|
@ -1826,13 +1826,16 @@ fn handle_kill_npcs(
|
|||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let to_kill = {
|
||||||
let ecs = server.state.ecs();
|
let ecs = server.state.ecs();
|
||||||
let mut healths = ecs.write_storage::<comp::Health>();
|
let entities = ecs.entities();
|
||||||
|
let healths = ecs.write_storage::<comp::Health>();
|
||||||
let players = ecs.read_storage::<comp::Player>();
|
let players = ecs.read_storage::<comp::Player>();
|
||||||
let alignments = ecs.read_storage::<Alignment>();
|
let alignments = ecs.read_storage::<Alignment>();
|
||||||
let mut count = 0;
|
|
||||||
|
|
||||||
for (mut health, (), alignment) in (&mut healths, !&players, alignments.maybe()).join() {
|
(&entities, &healths, !&players, alignments.maybe())
|
||||||
|
.join()
|
||||||
|
.filter_map(|(entity, _health, (), alignment)| {
|
||||||
let should_kill = kill_pets
|
let should_kill = kill_pets
|
||||||
|| if let Some(Alignment::Owned(owned)) = alignment {
|
|| if let Some(Alignment::Owned(owned)) = alignment {
|
||||||
ecs.entity_from_uid(owned.0)
|
ecs.entity_from_uid(owned.0)
|
||||||
@ -1841,12 +1844,17 @@ fn handle_kill_npcs(
|
|||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
if should_kill {
|
should_kill.then(|| entity)
|
||||||
count += 1;
|
})
|
||||||
health.kill();
|
.collect::<Vec<_>>()
|
||||||
|
};
|
||||||
|
let count = to_kill.len();
|
||||||
|
for entity in to_kill {
|
||||||
|
// Directly remove entities instead of modifying health to avoid loot drops.
|
||||||
|
if let Err(e) = server.state.delete_entity_recorded(entity) {
|
||||||
|
error!(?e, ?entity, "Failed to delete entity");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = if count > 0 {
|
let text = if count > 0 {
|
||||||
format!("Destroyed {} NPCs.", count)
|
format!("Destroyed {} NPCs.", count)
|
||||||
} else {
|
} else {
|
||||||
|
@ -129,15 +129,6 @@ pub fn handle_knockback(server: &Server, entity: EcsEntity, impulse: Vec3<f32>)
|
|||||||
/// other players. If the entity that killed it had stats, then give it exp for
|
/// other players. If the entity that killed it had stats, then give it exp for
|
||||||
/// the kill. Experience given is equal to the level of the entity that was
|
/// the kill. Experience given is equal to the level of the entity that was
|
||||||
/// killed times 10.
|
/// killed times 10.
|
||||||
// NOTE: Clippy incorrectly warns about a needless collect here because it does
|
|
||||||
// not understand that the pet count (which is computed during the first
|
|
||||||
// iteration over the members in range) is actually used by the second iteration
|
|
||||||
// over the members in range; since we have no way of knowing the pet count
|
|
||||||
// before the first loop finishes, we definitely need at least two loops. Then
|
|
||||||
// (currently) our only options are to store the member list in temporary space
|
|
||||||
// (e.g. by collecting to a vector), or to repeat the loop; but repeating the
|
|
||||||
// loop would currently be very inefficient since it has to rescan every entity
|
|
||||||
// on the server again.
|
|
||||||
pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: HealthChange) {
|
pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: HealthChange) {
|
||||||
let state = server.state_mut();
|
let state = server.state_mut();
|
||||||
|
|
||||||
@ -531,18 +522,11 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, last_change: Healt
|
|||||||
.destroy_entity(rtsim_entity.0);
|
.destroy_entity(rtsim_entity.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = state
|
println!("deleting");
|
||||||
.delete_entity_recorded(entity)
|
if let Err(e) = state.delete_entity_recorded(entity) {
|
||||||
.map_err(|e| error!(?e, ?entity, "Failed to delete destroyed entity"));
|
error!(?e, ?entity, "Failed to delete destroyed entity");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add Delete(time_left: Duration) component
|
|
||||||
/*
|
|
||||||
// If not a player delete the entity
|
|
||||||
if let Err(err) = state.delete_entity_recorded(entity) {
|
|
||||||
error!(?e, "Failed to delete destroyed entity");
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete an entity without any special actions (this is generally used for
|
/// Delete an entity without any special actions (this is generally used for
|
||||||
|
@ -25,9 +25,10 @@ use inventory_manip::handle_inventory;
|
|||||||
use invite::{handle_invite, handle_invite_response};
|
use invite::{handle_invite, handle_invite_response};
|
||||||
use player::{handle_client_disconnect, handle_exit_ingame, handle_possess};
|
use player::{handle_client_disconnect, handle_exit_ingame, handle_possess};
|
||||||
use specs::{Builder, Entity as EcsEntity, WorldExt};
|
use specs::{Builder, Entity as EcsEntity, WorldExt};
|
||||||
use trade::{cancel_trade_for, handle_process_trade_action};
|
use trade::handle_process_trade_action;
|
||||||
|
|
||||||
pub use group_manip::update_map_markers;
|
pub use group_manip::update_map_markers;
|
||||||
|
pub(crate) use trade::cancel_trades_for;
|
||||||
|
|
||||||
mod entity_creation;
|
mod entity_creation;
|
||||||
mod entity_manipulation;
|
mod entity_manipulation;
|
||||||
@ -165,7 +166,6 @@ impl Server {
|
|||||||
handle_loaded_character_data(self, entity, components);
|
handle_loaded_character_data(self, entity, components);
|
||||||
},
|
},
|
||||||
ServerEvent::ExitIngame { entity } => {
|
ServerEvent::ExitIngame { entity } => {
|
||||||
cancel_trade_for(self, entity);
|
|
||||||
handle_exit_ingame(self, entity);
|
handle_exit_ingame(self, entity);
|
||||||
},
|
},
|
||||||
ServerEvent::CreateNpc {
|
ServerEvent::CreateNpc {
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use super::Event;
|
use super::Event;
|
||||||
use crate::{
|
use crate::{
|
||||||
client::Client, events::trade::cancel_trade_for, metrics::PlayerMetrics,
|
client::Client, metrics::PlayerMetrics, persistence::character_updater::CharacterUpdater,
|
||||||
persistence::character_updater::CharacterUpdater, presence::Presence, state_ext::StateExt,
|
presence::Presence, state_ext::StateExt, BattleModeBuffer, Server,
|
||||||
BattleModeBuffer, Server,
|
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
comp,
|
comp,
|
||||||
@ -24,9 +23,17 @@ pub fn handle_exit_ingame(server: &mut Server, entity: EcsEntity) {
|
|||||||
let entity = persist_entity(state, entity);
|
let entity = persist_entity(state, entity);
|
||||||
|
|
||||||
// Create new entity with just `Client`, `Uid`, `Player`, and `...Stream`
|
// Create new entity with just `Client`, `Uid`, `Player`, and `...Stream`
|
||||||
// components Easier than checking and removing all other known components
|
// components.
|
||||||
|
//
|
||||||
|
// Easier than checking and removing all other known components.
|
||||||
|
//
|
||||||
// Note: If other `ServerEvent`s are referring to this entity they will be
|
// Note: If other `ServerEvent`s are referring to this entity they will be
|
||||||
// disrupted
|
// disrupted.
|
||||||
|
|
||||||
|
// Since we remove `Uid` below, any trades won't be cancelled by
|
||||||
|
// `delete_entity_recorded`. So we cancel the trade here. (maybe the trade
|
||||||
|
// key could be switched from `Uid` to `Entity`)
|
||||||
|
super::cancel_trades_for(state, entity);
|
||||||
|
|
||||||
let maybe_admin = state.ecs().write_storage::<comp::Admin>().remove(entity);
|
let maybe_admin = state.ecs().write_storage::<comp::Admin>().remove(entity);
|
||||||
let maybe_group = state
|
let maybe_group = state
|
||||||
@ -115,7 +122,6 @@ pub fn handle_client_disconnect(
|
|||||||
skip_persistence: bool,
|
skip_persistence: bool,
|
||||||
) -> Event {
|
) -> Event {
|
||||||
span!(_guard, "handle_client_disconnect");
|
span!(_guard, "handle_client_disconnect");
|
||||||
cancel_trade_for(server, entity);
|
|
||||||
if let Some(client) = server
|
if let Some(client) = server
|
||||||
.state()
|
.state()
|
||||||
.ecs()
|
.ecs()
|
||||||
|
@ -55,7 +55,7 @@ fn notify_agent_prices(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Invoked when the trade UI is up, handling item changes, accepts, etc
|
/// Invoked when the trade UI is up, handling item changes, accepts, etc
|
||||||
pub fn handle_process_trade_action(
|
pub(super) fn handle_process_trade_action(
|
||||||
server: &mut Server,
|
server: &mut Server,
|
||||||
entity: EcsEntity,
|
entity: EcsEntity,
|
||||||
trade_id: TradeId,
|
trade_id: TradeId,
|
||||||
@ -164,25 +164,30 @@ pub fn handle_process_trade_action(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Cancel all trades registered for a given UID.
|
/// Cancel all trades registered for a given UID.
|
||||||
pub fn cancel_trade_for(server: &mut Server, entity: EcsEntity) {
|
///
|
||||||
if let Some(uid) = server.state().ecs().uid_from_entity(entity) {
|
/// Note: This doesn't send any notification to the provided entity (only other
|
||||||
let mut trades = server.state.ecs().write_resource::<Trades>();
|
/// participants in the trade). It is assumed that the supplied entity either no
|
||||||
|
/// longer exists or is awareof this cancellation through other means (e.g.
|
||||||
|
/// client getting ExitInGameSuccess message knows that it should clear any
|
||||||
|
/// trades).
|
||||||
|
pub(crate) fn cancel_trades_for(state: &mut common_state::State, entity: EcsEntity) {
|
||||||
|
let ecs = state.ecs();
|
||||||
|
if let Some(uid) = ecs.uid_from_entity(entity) {
|
||||||
|
let mut trades = ecs.write_resource::<Trades>();
|
||||||
|
|
||||||
let active_trade = match trades.entity_trades.get(&uid) {
|
let active_trade = match trades.entity_trades.get(&uid) {
|
||||||
Some(n) => *n,
|
Some(n) => *n,
|
||||||
None => {
|
None => return,
|
||||||
return;
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let to_notify = trades.decline_trade(active_trade, uid);
|
let to_notify = trades.decline_trade(active_trade, uid);
|
||||||
to_notify
|
to_notify.and_then(|u| ecs.entity_from_uid(u.0)).map(|e| {
|
||||||
.and_then(|u| server.state.ecs().entity_from_uid(u.0))
|
if let Some(c) = ecs.read_storage::<crate::Client>().get(e) {
|
||||||
.map(|e| {
|
c.send_fallible(ServerGeneral::FinishedTrade(TradeResult::Declined));
|
||||||
server.notify_client(e, ServerGeneral::FinishedTrade(TradeResult::Declined));
|
}
|
||||||
notify_agent_simple(
|
notify_agent_simple(
|
||||||
server.state.ecs().write_storage::<Agent>(),
|
ecs.write_storage::<Agent>(),
|
||||||
e,
|
e,
|
||||||
AgentEvent::FinishedTrade(TradeResult::Declined),
|
AgentEvent::FinishedTrade(TradeResult::Declined),
|
||||||
);
|
);
|
||||||
|
@ -1172,11 +1172,9 @@ impl Server {
|
|||||||
where
|
where
|
||||||
S: Into<ServerMsg>,
|
S: Into<ServerMsg>,
|
||||||
{
|
{
|
||||||
self.state
|
if let Some(client) = self.state.ecs().read_storage::<Client>().get(entity) {
|
||||||
.ecs()
|
client.send_fallible(msg);
|
||||||
.read_storage::<Client>()
|
}
|
||||||
.get(entity)
|
|
||||||
.map(|c| c.send(msg));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn notify_players(&mut self, msg: ServerGeneral) { self.state.notify_players(msg); }
|
pub fn notify_players(&mut self, msg: ServerGeneral) { self.state.notify_players(msg); }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
automod::AutoMod,
|
automod::AutoMod,
|
||||||
client::Client,
|
client::Client,
|
||||||
events::update_map_markers,
|
events::{self, update_map_markers},
|
||||||
persistence::PersistedComponents,
|
persistence::PersistedComponents,
|
||||||
pet::restore_pet,
|
pet::restore_pet,
|
||||||
presence::{Presence, RepositionOnChunkLoad},
|
presence::{Presence, RepositionOnChunkLoad},
|
||||||
@ -1000,10 +1000,14 @@ impl StateExt for State {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cancel extant trades
|
||||||
|
events::cancel_trades_for(self, entity);
|
||||||
|
|
||||||
let (maybe_uid, maybe_pos) = (
|
let (maybe_uid, maybe_pos) = (
|
||||||
self.ecs().read_storage::<Uid>().get(entity).copied(),
|
self.ecs().read_storage::<Uid>().get(entity).copied(),
|
||||||
self.ecs().read_storage::<comp::Pos>().get(entity).copied(),
|
self.ecs().read_storage::<comp::Pos>().get(entity).copied(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let res = self.ecs_mut().delete_entity(entity);
|
let res = self.ecs_mut().delete_entity(entity);
|
||||||
if res.is_ok() {
|
if res.is_ok() {
|
||||||
if let (Some(uid), Some(pos)) = (maybe_uid, maybe_pos) {
|
if let (Some(uid), Some(pos)) = (maybe_uid, maybe_pos) {
|
||||||
|
Loading…
Reference in New Issue
Block a user