Merge branch 'knarkzel/fix-npc-spawn' into 'master'

Fix bug that caused campfires and other stuff to duplicate

See merge request veloren/veloren!1543
This commit is contained in:
Joshua Barretto 2020-11-22 21:03:06 +00:00
commit da9b23d4f6
8 changed files with 36 additions and 11 deletions

View File

@ -81,6 +81,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Adjusted some keybindings
- Consumables can now trigger multiple effects and buffs
- Overhauled overworld spawns depending on chunk attributes
- Fixed a bug which caused campfires and other stuff to duplicate
### Removed

View File

@ -0,0 +1,13 @@
use specs::Component;
use specs_idvs::IdvStorage;
use vek::Vec2;
/// This component exists in order to fix a bug that caused entitites
/// such as campfires to duplicate because the chunk was double-loaded.
/// See https://gitlab.com/veloren/veloren/-/merge_requests/1543
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct HomeChunk(pub Vec2<i32>);
impl Component for HomeChunk {
type Storage = IdvStorage<Self>;
}

View File

@ -10,6 +10,7 @@ mod controller;
mod energy;
pub mod group;
mod health;
pub mod home_chunk;
mod inputs;
mod inventory;
mod last;
@ -47,6 +48,7 @@ pub use controller::{
pub use energy::{Energy, EnergyChange, EnergySource};
pub use group::Group;
pub use health::{Health, HealthChange, HealthSource};
pub use home_chunk::HomeChunk;
pub use inputs::CanBuild;
pub use inventory::{
item,

View File

@ -104,6 +104,7 @@ pub enum ServerEvent {
agent: Option<comp::Agent>,
alignment: comp::Alignment,
scale: comp::Scale,
home_chunk: Option<comp::HomeChunk>,
drop_item: Option<Item>,
},
CreateWaypoint(Vec3<f32>),

View File

@ -2,7 +2,7 @@ use crate::{sys, Server, StateExt};
use common::{
character::CharacterId,
comp::{
self, beam, shockwave, Agent, Alignment, Body, Gravity, Health, Item, ItemDrop,
self, beam, shockwave, Agent, Alignment, Body, Gravity, Health, HomeChunk, Item, ItemDrop,
LightEmitter, Loadout, Ori, Pos, Projectile, Scale, Stats, Vel, WaypointArea,
},
outcome::Outcome,
@ -49,6 +49,7 @@ pub fn handle_create_npc(
alignment: Alignment,
scale: Scale,
drop_item: Option<Item>,
home_chunk: Option<HomeChunk>,
) {
let group = match alignment {
Alignment::Wild => None,
@ -83,6 +84,12 @@ pub fn handle_create_npc(
entity
};
let entity = if let Some(home_chunk) = home_chunk {
entity.with(home_chunk)
} else {
entity
};
entity.build();
}

View File

@ -115,9 +115,11 @@ impl Server {
agent,
alignment,
scale,
home_chunk,
drop_item,
} => handle_create_npc(
self, pos, stats, health, loadout, body, agent, alignment, scale, drop_item,
home_chunk,
),
ServerEvent::CreateWaypoint(pos) => handle_create_waypoint(self, pos),
ServerEvent::ClientDisconnect(entity) => {

View File

@ -54,7 +54,6 @@ use common::{
},
outcome::Outcome,
recipe::default_recipe_book,
spiral::Spiral2d,
state::{State, TimeOfDay},
sync::WorldSyncExt,
terrain::TerrainChunkSize,
@ -197,6 +196,7 @@ impl Server {
state.ecs_mut().register::<RegionSubscription>();
state.ecs_mut().register::<Client>();
state.ecs_mut().register::<Presence>();
state.ecs_mut().register::<comp::HomeChunk>();
//Alias validator
let banned_words_paths = &settings.banned_words_files;
@ -524,19 +524,17 @@ impl Server {
&self.state.ecs().entities(),
&self.state.ecs().read_storage::<comp::Pos>(),
!&self.state.ecs().read_storage::<comp::Player>(),
&self.state.ecs().read_storage::<comp::HomeChunk>(),
)
.join()
.filter(|(_, pos, _)| {
.filter(|(_, pos, _, home_chunk)| {
let chunk_key = terrain.pos_key(pos.0.map(|e| e.floor() as i32));
// Check not only this chunk, but also all neighbours to avoid immediate
// despawning if the entity walks outside of a valid chunk
// briefly. If the entity isn't even near a loaded chunk then we get
// rid of it.
Spiral2d::new()
.take(9)
.all(|offs| terrain.get_key(chunk_key + offs).is_none())
// Check if both this chunk and the NPCs `home_chunk` is unloaded. If so,
// we delete them. We check for `home_chunk` in order to avoid duplicating
// the entity under some circumstances.
terrain.get_key(chunk_key).is_none() && terrain.get_key(home_chunk.0).is_none()
})
.map(|(entity, _, _)| entity)
.map(|(entity, _, _, _)| entity)
.collect::<Vec<_>>()
};

View File

@ -187,6 +187,7 @@ impl<'a> System<'a> for Sys {
body,
alignment,
scale: comp::Scale(scale),
home_chunk: Some(comp::HomeChunk(key)),
drop_item: entity.loot_drop,
})
}