From 650ef9a5e23c5c3cd785046855d8cbb496dbe0d0 Mon Sep 17 00:00:00 2001 From: flo Date: Sun, 15 Jan 2023 18:28:38 +0000 Subject: [PATCH] autodelete of summoned sprites --- Cargo.lock | 10 +++ .../arthropods/blackwidow/ensnaringwebs.ron | 1 + .../arthropods/tarantula/ensnaringwebs.ron | 1 + .../abilities/custom/dagon/seaurchins.ron | 1 + .../custom/harvester/ensnaringvines.ron | 1 + common/src/comp/ability.rs | 4 ++ common/src/event.rs | 1 + common/src/outcome.rs | 7 +- common/src/states/sprite_summon.rs | 3 + common/state/Cargo.toml | 1 + common/state/src/state.rs | 67 ++++++++++++++++++- server/src/events/interaction.rs | 30 +++++++-- server/src/events/mod.rs | 8 ++- voxygen/src/audio/sfx/mod.rs | 19 +++++- voxygen/src/scene/particle.rs | 17 ++++- 15 files changed, 157 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a760d441ac..a09b0cd784 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6177,6 +6177,15 @@ dependencies = [ "num_threads", ] +[[package]] +name = "timer-queue" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13756c29c43d836ff576221498bf4916b0d2f7ea24cd47d3531b70dc4341f038" +dependencies = [ + "slab", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -6826,6 +6835,7 @@ dependencies = [ "serde", "specs", "tar", + "timer-queue", "toml", "tracing", "vek 0.15.8", diff --git a/assets/common/abilities/custom/arthropods/blackwidow/ensnaringwebs.ron b/assets/common/abilities/custom/arthropods/blackwidow/ensnaringwebs.ron index a22afda2e7..b5d5b0ff70 100644 --- a/assets/common/abilities/custom/arthropods/blackwidow/ensnaringwebs.ron +++ b/assets/common/abilities/custom/arthropods/blackwidow/ensnaringwebs.ron @@ -3,6 +3,7 @@ SpriteSummon( cast_duration: 0.4, recover_duration: 0.3, sprite: EnsnaringWeb, + del_timeout: None, summon_distance: (0, 10), sparseness: 0.76, ) \ No newline at end of file diff --git a/assets/common/abilities/custom/arthropods/tarantula/ensnaringwebs.ron b/assets/common/abilities/custom/arthropods/tarantula/ensnaringwebs.ron index ec486d6c19..da0bfab83d 100644 --- a/assets/common/abilities/custom/arthropods/tarantula/ensnaringwebs.ron +++ b/assets/common/abilities/custom/arthropods/tarantula/ensnaringwebs.ron @@ -3,6 +3,7 @@ SpriteSummon( cast_duration: 0.4, recover_duration: 0.3, sprite: EnsnaringWeb, + del_timeout: None, summon_distance: (0, 9), sparseness: 0.8, ) \ No newline at end of file diff --git a/assets/common/abilities/custom/dagon/seaurchins.ron b/assets/common/abilities/custom/dagon/seaurchins.ron index 0f01e6868f..f07f55f428 100644 --- a/assets/common/abilities/custom/dagon/seaurchins.ron +++ b/assets/common/abilities/custom/dagon/seaurchins.ron @@ -3,6 +3,7 @@ SpriteSummon( cast_duration: 0.1, recover_duration: 0.9, sprite: SeaUrchin, + del_timeout: Some((4, 5)), summon_distance: (5, 3.1), sparseness: 0.2, ) \ No newline at end of file diff --git a/assets/common/abilities/custom/harvester/ensnaringvines.ron b/assets/common/abilities/custom/harvester/ensnaringvines.ron index e050dc8241..2a5c82f908 100644 --- a/assets/common/abilities/custom/harvester/ensnaringvines.ron +++ b/assets/common/abilities/custom/harvester/ensnaringvines.ron @@ -3,6 +3,7 @@ SpriteSummon( cast_duration: 0.4, recover_duration: 0.3, sprite: EnsnaringVines, + del_timeout: None, summon_distance: (0, 25), sparseness: 0.67, ) \ No newline at end of file diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 045fe24efb..fe51ea06fc 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -700,6 +700,7 @@ pub enum CharacterAbility { cast_duration: f32, recover_duration: f32, sprite: SpriteKind, + del_timeout: Option<(f32, f32)>, summon_distance: (f32, f32), sparseness: f64, #[serde(default)] @@ -1275,6 +1276,7 @@ impl CharacterAbility { ref mut cast_duration, ref mut recover_duration, sprite: _, + del_timeout: _, summon_distance: (ref mut inner_dist, ref mut outer_dist), sparseness: _, meta: _, @@ -2508,6 +2510,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { cast_duration, recover_duration, sprite, + del_timeout, summon_distance, sparseness, meta: _, @@ -2517,6 +2520,7 @@ impl From<(&CharacterAbility, AbilityInfo, &JoinData<'_>)> for CharacterState { cast_duration: Duration::from_secs_f32(*cast_duration), recover_duration: Duration::from_secs_f32(*recover_duration), sprite: *sprite, + del_timeout: *del_timeout, summon_distance: *summon_distance, sparseness: *sparseness, ability_info, diff --git a/common/src/event.rs b/common/src/event.rs index 6b030b6d4d..14a3394f20 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -208,6 +208,7 @@ pub enum ServerEvent { CreateSprite { pos: Vec3, sprite: SpriteKind, + del_timeout: Option<(f32, f32)>, }, TamePet { pet_entity: EcsEntity, diff --git a/common/src/outcome.rs b/common/src/outcome.rs index b0a2ebc963..6eb9dcfc3d 100644 --- a/common/src/outcome.rs +++ b/common/src/outcome.rs @@ -1,4 +1,4 @@ -use crate::{combat::DamageContributor, comp, uid::Uid, DamageSource}; +use crate::{combat::DamageContributor, comp, uid::Uid, DamageSource, terrain::SpriteKind}; use comp::{beam, item::Reagent, poise::PoiseState, skillset::SkillGroupKind, UtteranceKind}; use hashbrown::HashSet; use serde::{Deserialize, Serialize}; @@ -97,6 +97,10 @@ pub enum Outcome { pos: Vec3, wielded: bool, }, + SpriteDelete { + pos: Vec3, + sprite: SpriteKind, + }, } impl Outcome { @@ -115,6 +119,7 @@ impl Outcome { | Outcome::PoiseChange { pos, .. } | Outcome::GroundSlam { pos } | Outcome::Utterance { pos, .. } + | Outcome::SpriteDelete { pos, .. } | Outcome::Glider { pos, .. } => Some(*pos), Outcome::BreakBlock { pos, .. } => Some(pos.map(|e| e as f32 + 0.5)), Outcome::ExpChange { .. } diff --git a/common/src/states/sprite_summon.rs b/common/src/states/sprite_summon.rs index 72c977aaa6..fbcbb0ea90 100644 --- a/common/src/states/sprite_summon.rs +++ b/common/src/states/sprite_summon.rs @@ -25,6 +25,8 @@ pub struct StaticData { pub recover_duration: Duration, /// What kind of sprite is created by this state pub sprite: SpriteKind, + /// Duration until sprite-delete begins (in sec), randomization-range of sprite-delete-time (in sec) + pub del_timeout: Option<(f32, f32)>, /// Range that sprites are created relative to the summonner pub summon_distance: (f32, f32), /// Chance that sprite is not created on a particular square @@ -127,6 +129,7 @@ impl CharacterBehavior for Data { output_events.emit_server(ServerEvent::CreateSprite { pos: Vec3::new(sprite_pos.x, sprite_pos.y, z + i), sprite: self.static_data.sprite, + del_timeout: self.static_data.del_timeout, }); } } diff --git a/common/state/Cargo.toml b/common/state/Cargo.toml index b5e9063e0d..9ad729f934 100644 --- a/common/state/Cargo.toml +++ b/common/state/Cargo.toml @@ -35,6 +35,7 @@ tar = { version = "0.4.37", optional = true } wasmer = { version = "2.0.0", optional = true, default-features = false, features = ["wat", "default-cranelift", "default-universal"] } bincode = { version = "1.3.1", optional = true } plugin-api = { package = "veloren-plugin-api", path = "../../plugin/api", optional = true } +timer-queue = "0.1.0" # Tweak running code #inline_tweak = { version = "1.0.8", features = ["release_tweak"] } diff --git a/common/state/src/state.rs b/common/state/src/state.rs index de1d7c7d3b..8c15a4349b 100644 --- a/common/state/src/state.rs +++ b/common/state/src/state.rs @@ -36,18 +36,20 @@ use specs::{ Component, DispatcherBuilder, Entity as EcsEntity, WorldExt, }; use std::sync::Arc; +use timer_queue::TimerQueue; use vek::*; /// How much faster should an in-game day be compared to a real day? // TODO: Don't hard-code this. const DAY_CYCLE_FACTOR: f64 = 24.0 * 2.0; - /// At what point should we stop speeding up physics to compensate for lag? If /// we speed physics up too fast, we'd skip important physics events like /// collisions. This constant determines the upper limit. If delta time exceeds /// this value, the game's physics will begin to produce time lag. Ideally, we'd /// avoid such a situation. const MAX_DELTA_TIME: f32 = 1.0; +/// convert seconds to milliseconds to use in TimerQueue +const SECONDS_TO_MILLISECONDS: f64 = 1000.0; #[derive(Default)] pub struct BlockChange { @@ -69,6 +71,29 @@ impl BlockChange { pub fn clear(&mut self) { self.blocks.clear(); } } +#[derive(Default)] +pub struct ScheduledBlockChange { + changes: TimerQueue, Block>>, + outcomes: TimerQueue, Block>>, +} +impl ScheduledBlockChange { + pub fn set(&mut self, pos: Vec3, block: Block, replace_time: f64) { + let timer = self.changes.insert( + (replace_time * SECONDS_TO_MILLISECONDS) as u64, + HashMap::new(), + ); + self.changes.get_mut(timer).insert(pos, block); + } + + pub fn outcome_set(&mut self, pos: Vec3, block: Block, replace_time: f64) { + let outcome_timer = self.outcomes.insert( + (replace_time * SECONDS_TO_MILLISECONDS) as u64, + HashMap::new(), + ); + self.outcomes.get_mut(outcome_timer).insert(pos, block); + } +} + #[derive(Default)] pub struct TerrainChanges { pub new_chunks: HashSet>, @@ -234,6 +259,7 @@ impl State { ecs.insert(PlayerEntity(None)); ecs.insert(TerrainGrid::new(map_size_lg, default_chunk).unwrap()); ecs.insert(BlockChange::default()); + ecs.insert(ScheduledBlockChange::default()); ecs.insert(crate::build_areas::BuildAreas::default()); ecs.insert(TerrainChanges::default()); ecs.insert(EventBus::::default()); @@ -415,6 +441,23 @@ impl State { self.ecs.write_resource::().set(pos, block); } + /// Set a block in this state's terrain (used to delete temporary summoned + /// sprites after a timeout). + pub fn schedule_set_block( + &self, + pos: Vec3, + block: Block, + sprite_block: Block, + replace_time: f64, + ) { + self.ecs + .write_resource::() + .set(pos, block, replace_time); + self.ecs + .write_resource::() + .outcome_set(pos, sprite_block, replace_time); + } + /// Check if the block at given position `pos` has already been modified /// this tick. pub fn can_set_block(&self, pos: Vec3) -> bool { @@ -500,6 +543,28 @@ impl State { let mut terrain = self.ecs.write_resource::(); let mut modified_blocks = std::mem::take(&mut self.ecs.write_resource::().blocks); + + let mut scheduled_changes = self.ecs.write_resource::(); + let current_time: f64 = self.ecs.read_resource::