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,
active_abilities: ActiveAbilities,
can_build: CanBuild,
object: Object,
}
};
}
@ -253,3 +254,7 @@ impl NetSync for ActiveAbilities {
impl NetSync for CanBuild {
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 crate::uid::Uid;
use crate::{resources::Time, uid::Uid};
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 {
Bomb {
owner: Option<Uid>,
@ -12,8 +13,12 @@ pub enum Object {
owner: Option<Uid>,
reagent: Reagent,
},
DeleteAfter {
spawned_at: Time,
timeout: Duration,
},
}
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,
item::{ItemKind, MaterialStatManifest},
skills::{GeneralSkill, Skill},
ChatType, Group, Inventory, Item, LootOwner, Player, Poise, Presence, PresenceKind,
ChatType, Group, Inventory, Item, LootOwner, Object, Player, Poise, Presence, PresenceKind,
},
effect::Effect,
link::{Link, LinkHandle},
@ -40,7 +40,7 @@ use specs::{
saveload::MarkerAllocator, Builder, Entity as EcsEntity, EntityBuilder as EcsEntityBuilder,
Join, WorldExt,
};
use std::time::Instant;
use std::time::{Duration, Instant};
use tracing::{trace, warn};
use vek::*;
@ -366,6 +366,8 @@ impl StateExt for State {
// 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 body = comp::Body::ItemDrop(item_drop);
let light_emitter = match &*item.kind() {
@ -388,6 +390,11 @@ impl StateExt for State {
.with(item_drop.density())
.with(body.collider())
.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(light_emitter)
.build(),

View File

@ -2,11 +2,11 @@ use common::{
comp::{Object, PhysicsState, Pos, Vel},
effect::Effect,
event::{EventBus, ServerEvent},
resources::DeltaTime,
resources::{DeltaTime, Time},
Damage, DamageKind, DamageSource, Explosion, RadiusEffect,
};
use common_ecs::{Job, Origin, Phase, System};
use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
use specs::{Entities, Join, Read, ReadStorage};
use vek::Rgb;
/// This system is responsible for handling misc object behaviours
@ -16,11 +16,12 @@ impl<'a> System<'a> for Sys {
type SystemData = (
Entities<'a>,
Read<'a, DeltaTime>,
Read<'a, Time>,
Read<'a, EventBus<ServerEvent>>,
ReadStorage<'a, Pos>,
ReadStorage<'a, Vel>,
ReadStorage<'a, PhysicsState>,
WriteStorage<'a, Object>,
ReadStorage<'a, Object>,
);
const NAME: &'static str = "object";
@ -29,7 +30,7 @@ impl<'a> System<'a> for Sys {
fn run(
_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();
@ -39,7 +40,7 @@ impl<'a> System<'a> for Sys {
&positions,
&velocities,
&physics_states,
&mut objects,
&objects,
)
.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},
ship::{self, figuredata::VOXEL_COLLIDER_MANIFEST},
Body, CharacterActivity, CharacterState, Collider, Controller, Health, Inventory, Item,
ItemKey, Last, LightAnimation, LightEmitter, Ori, PhysicsState, PoiseState, Pos, Scale,
SkillSet, Stance, Vel,
ItemKey, Last, LightAnimation, LightEmitter, Object, Ori, PhysicsState, PoiseState, Pos,
Scale, SkillSet, Stance, Vel,
},
link::Is,
mounting::{Rider, VolumeRider},
@ -6394,6 +6394,7 @@ impl FigureMgr {
filter_state: impl Fn(&FigureStateMeta) -> bool,
) {
let ecs = state.ecs();
let time = ecs.read_resource::<Time>();
let items = ecs.read_storage::<Item>();
(
&ecs.entities(),
@ -6404,11 +6405,13 @@ impl FigureMgr {
ecs.read_storage::<Inventory>().maybe(),
ecs.read_storage::<Scale>().maybe(),
ecs.read_storage::<Collider>().maybe(),
ecs.read_storage::<Object>().maybe(),
)
.join()
// Don't render dead entities
.filter(|(_, _, _, _, health, _, _, _)| health.map_or(true, |h| !h.is_dead))
.for_each(|(entity, pos, _, body, _, inventory, scale, collider)| {
.filter(|(_, _, _, _, health, _, _, _, _)| health.map_or(true, |h| !h.is_dead))
.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(
tick,
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>(
&'a self,
drawer: &mut FigureDrawer<'_, 'a>,
@ -6552,10 +6568,11 @@ impl FigureMgr {
span!(_guard, "render", "FigureManager::render");
let ecs = state.ecs();
let time = ecs.read_resource::<Time>();
let character_state_storage = state.read_storage::<CharacterState>();
let character_state = character_state_storage.get(viewpoint_entity);
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.read_storage::<Pos>(),
&ecs.read_storage::<Body>(),
@ -6563,12 +6580,14 @@ impl FigureMgr {
ecs.read_storage::<Inventory>().maybe(),
ecs.read_storage::<Scale>().maybe(),
ecs.read_storage::<Collider>().maybe(),
ecs.read_storage::<Object>().maybe(),
)
.join()
// 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
.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(
tick,