Make items vanish after 5 minutes

This commit is contained in:
Joshua Barretto 2023-06-01 14:51:19 +01:00
parent 3a383050d5
commit ec3a7d1898
5 changed files with 63 additions and 18 deletions

View File

@ -64,6 +64,7 @@ macro_rules! synced_components {
combo: Combo, combo: Combo,
active_abilities: ActiveAbilities, active_abilities: ActiveAbilities,
can_build: CanBuild, can_build: CanBuild,
object: Object,
} }
}; };
} }
@ -253,3 +254,7 @@ impl NetSync for ActiveAbilities {
impl NetSync for CanBuild { impl NetSync for CanBuild {
const SYNC_FROM: SyncFrom = SyncFrom::ClientEntity; const SYNC_FROM: SyncFrom = SyncFrom::ClientEntity;
} }
impl NetSync for Object {
const SYNC_FROM: SyncFrom = SyncFrom::AnyEntity;
}

View File

@ -1,9 +1,10 @@
use super::item::Reagent; use super::item::Reagent;
use crate::uid::Uid; use crate::{resources::Time, uid::Uid};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use specs::Component; use specs::{Component, DerefFlaggedStorage};
use std::time::Duration;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Object { pub enum Object {
Bomb { Bomb {
owner: Option<Uid>, owner: Option<Uid>,
@ -12,8 +13,12 @@ pub enum Object {
owner: Option<Uid>, owner: Option<Uid>,
reagent: Reagent, reagent: Reagent,
}, },
DeleteAfter {
spawned_at: Time,
timeout: Duration,
},
} }
impl Component for Object { impl Component for Object {
type Storage = specs::VecStorage<Self>; type Storage = DerefFlaggedStorage<Self, specs::VecStorage<Self>>;
} }

View File

@ -19,7 +19,7 @@ use common::{
self, self,
item::{ItemKind, MaterialStatManifest}, item::{ItemKind, MaterialStatManifest},
skills::{GeneralSkill, Skill}, skills::{GeneralSkill, Skill},
ChatType, Group, Inventory, Item, LootOwner, Player, Poise, Presence, PresenceKind, ChatType, Group, Inventory, Item, LootOwner, Object, Player, Poise, Presence, PresenceKind,
}, },
effect::Effect, effect::Effect,
link::{Link, LinkHandle}, link::{Link, LinkHandle},
@ -40,7 +40,7 @@ use specs::{
saveload::MarkerAllocator, Builder, Entity as EcsEntity, EntityBuilder as EcsEntityBuilder, saveload::MarkerAllocator, Builder, Entity as EcsEntity, EntityBuilder as EcsEntityBuilder,
Join, WorldExt, Join, WorldExt,
}; };
use std::time::Instant; use std::time::{Duration, Instant};
use tracing::{trace, warn}; use tracing::{trace, warn};
use vek::*; use vek::*;
@ -366,6 +366,8 @@ impl StateExt for State {
// Only if merging items fails do we give up and create a new item // Only if merging items fails do we give up and create a new item
} }
let spawned_at = *self.ecs().read_resource::<Time>();
let item_drop = comp::item_drop::Body::from(&item); let item_drop = comp::item_drop::Body::from(&item);
let body = comp::Body::ItemDrop(item_drop); let body = comp::Body::ItemDrop(item_drop);
let light_emitter = match &*item.kind() { let light_emitter = match &*item.kind() {
@ -388,6 +390,11 @@ impl StateExt for State {
.with(item_drop.density()) .with(item_drop.density())
.with(body.collider()) .with(body.collider())
.with(body) .with(body)
.with(Object::DeleteAfter {
spawned_at,
// Delete the item drop after 5 minutes
timeout: Duration::from_secs(300),
})
.maybe_with(loot_owner) .maybe_with(loot_owner)
.maybe_with(light_emitter) .maybe_with(light_emitter)
.build(), .build(),

View File

@ -2,11 +2,11 @@ use common::{
comp::{Object, PhysicsState, Pos, Vel}, comp::{Object, PhysicsState, Pos, Vel},
effect::Effect, effect::Effect,
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
resources::DeltaTime, resources::{DeltaTime, Time},
Damage, DamageKind, DamageSource, Explosion, RadiusEffect, Damage, DamageKind, DamageSource, Explosion, RadiusEffect,
}; };
use common_ecs::{Job, Origin, Phase, System}; use common_ecs::{Job, Origin, Phase, System};
use specs::{Entities, Join, Read, ReadStorage, WriteStorage}; use specs::{Entities, Join, Read, ReadStorage};
use vek::Rgb; use vek::Rgb;
/// This system is responsible for handling misc object behaviours /// This system is responsible for handling misc object behaviours
@ -16,11 +16,12 @@ impl<'a> System<'a> for Sys {
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
Read<'a, DeltaTime>, Read<'a, DeltaTime>,
Read<'a, Time>,
Read<'a, EventBus<ServerEvent>>, Read<'a, EventBus<ServerEvent>>,
ReadStorage<'a, Pos>, ReadStorage<'a, Pos>,
ReadStorage<'a, Vel>, ReadStorage<'a, Vel>,
ReadStorage<'a, PhysicsState>, ReadStorage<'a, PhysicsState>,
WriteStorage<'a, Object>, ReadStorage<'a, Object>,
); );
const NAME: &'static str = "object"; const NAME: &'static str = "object";
@ -29,7 +30,7 @@ impl<'a> System<'a> for Sys {
fn run( fn run(
_job: &mut Job<Self>, _job: &mut Job<Self>,
(entities, _dt, server_bus, positions, velocities, physics_states, mut objects): Self::SystemData, (entities, _dt, time, server_bus, positions, velocities, physics_states, objects): Self::SystemData,
) { ) {
let mut server_emitter = server_bus.emitter(); let mut server_emitter = server_bus.emitter();
@ -39,7 +40,7 @@ impl<'a> System<'a> for Sys {
&positions, &positions,
&velocities, &velocities,
&physics_states, &physics_states,
&mut objects, &objects,
) )
.join() .join()
{ {
@ -160,6 +161,14 @@ impl<'a> System<'a> for Sys {
}); });
} }
}, },
Object::DeleteAfter {
spawned_at,
timeout,
} => {
if (time.0 - spawned_at.0).max(0.0) > timeout.as_secs_f64() {
server_emitter.emit(ServerEvent::Delete(entity));
}
},
} }
} }
} }

View File

@ -40,8 +40,8 @@ use common::{
item::{tool::AbilityContext, Hands, ItemKind, ToolKind}, item::{tool::AbilityContext, Hands, ItemKind, ToolKind},
ship::{self, figuredata::VOXEL_COLLIDER_MANIFEST}, ship::{self, figuredata::VOXEL_COLLIDER_MANIFEST},
Body, CharacterActivity, CharacterState, Collider, Controller, Health, Inventory, Item, Body, CharacterActivity, CharacterState, Collider, Controller, Health, Inventory, Item,
ItemKey, Last, LightAnimation, LightEmitter, Ori, PhysicsState, PoiseState, Pos, Scale, ItemKey, Last, LightAnimation, LightEmitter, Object, Ori, PhysicsState, PoiseState, Pos,
SkillSet, Stance, Vel, Scale, SkillSet, Stance, Vel,
}, },
link::Is, link::Is,
mounting::{Rider, VolumeRider}, mounting::{Rider, VolumeRider},
@ -6394,6 +6394,7 @@ impl FigureMgr {
filter_state: impl Fn(&FigureStateMeta) -> bool, filter_state: impl Fn(&FigureStateMeta) -> bool,
) { ) {
let ecs = state.ecs(); let ecs = state.ecs();
let time = ecs.read_resource::<Time>();
let items = ecs.read_storage::<Item>(); let items = ecs.read_storage::<Item>();
( (
&ecs.entities(), &ecs.entities(),
@ -6404,11 +6405,13 @@ impl FigureMgr {
ecs.read_storage::<Inventory>().maybe(), ecs.read_storage::<Inventory>().maybe(),
ecs.read_storage::<Scale>().maybe(), ecs.read_storage::<Scale>().maybe(),
ecs.read_storage::<Collider>().maybe(), ecs.read_storage::<Collider>().maybe(),
ecs.read_storage::<Object>().maybe(),
) )
.join() .join()
// Don't render dead entities // Don't render dead entities
.filter(|(_, _, _, _, health, _, _, _)| health.map_or(true, |h| !h.is_dead)) .filter(|(_, _, _, _, health, _, _, _, _)| health.map_or(true, |h| !h.is_dead))
.for_each(|(entity, pos, _, body, _, inventory, scale, collider)| { .filter(|(_, _, _, _, _, _, _, _, obj)| !self.should_flicker(*time, *obj))
.for_each(|(entity, pos, _, body, _, inventory, scale, collider, _)| {
if let Some((bound, model, _)) = self.get_model_for_render( if let Some((bound, model, _)) = self.get_model_for_render(
tick, tick,
camera, camera,
@ -6541,6 +6544,19 @@ impl FigureMgr {
} }
} }
// Returns `true` if an object should flicker because it's about to vanish
fn should_flicker(&self, time: Time, obj: Option<&Object>) -> bool {
if let Some(Object::DeleteAfter {
spawned_at,
timeout,
}) = obj
{
time.0 > spawned_at.0 + timeout.as_secs_f64() - 10.0 && (time.0 * 8.0).fract() < 0.5
} else {
false
}
}
pub fn render<'a>( pub fn render<'a>(
&'a self, &'a self,
drawer: &mut FigureDrawer<'_, 'a>, drawer: &mut FigureDrawer<'_, 'a>,
@ -6552,10 +6568,11 @@ impl FigureMgr {
span!(_guard, "render", "FigureManager::render"); span!(_guard, "render", "FigureManager::render");
let ecs = state.ecs(); let ecs = state.ecs();
let time = ecs.read_resource::<Time>();
let character_state_storage = state.read_storage::<CharacterState>(); let character_state_storage = state.read_storage::<CharacterState>();
let character_state = character_state_storage.get(viewpoint_entity); let character_state = character_state_storage.get(viewpoint_entity);
let items = ecs.read_storage::<Item>(); let items = ecs.read_storage::<Item>();
for (entity, pos, body, _, inventory, scale, collider) in ( for (entity, pos, body, _, inventory, scale, collider, _) in (
&ecs.entities(), &ecs.entities(),
&ecs.read_storage::<Pos>(), &ecs.read_storage::<Pos>(),
&ecs.read_storage::<Body>(), &ecs.read_storage::<Body>(),
@ -6563,12 +6580,14 @@ impl FigureMgr {
ecs.read_storage::<Inventory>().maybe(), ecs.read_storage::<Inventory>().maybe(),
ecs.read_storage::<Scale>().maybe(), ecs.read_storage::<Scale>().maybe(),
ecs.read_storage::<Collider>().maybe(), ecs.read_storage::<Collider>().maybe(),
ecs.read_storage::<Object>().maybe(),
) )
.join() .join()
// Don't render dead entities // Don't render dead entities
.filter(|(_, _, _, health, _, _, _)| health.map_or(true, |h| !h.is_dead)) .filter(|(_, _, _, health, _, _, _, _)| health.map_or(true, |h| !h.is_dead))
// Don't render player // Don't render player
.filter(|(entity, _, _, _, _, _, _)| *entity != viewpoint_entity) .filter(|(entity, _, _, _, _, _, _, _)| *entity != viewpoint_entity)
.filter(|(_, _, _, _, _, _, _, obj)| !self.should_flicker(*time, *obj))
{ {
if let Some((bound, model, atlas)) = self.get_model_for_render( if let Some((bound, model, atlas)) = self.get_model_for_render(
tick, tick,