veloren_common/
event.rs

1use crate::{
2    Explosion,
3    character::CharacterId,
4    combat::{AttackSource, DeathEffects, RiderEffects},
5    comp::{
6        self, DisconnectReason, LootOwner, Ori, Pos, UnresolvedChatMsg, Vel,
7        agent::Sound,
8        invite::{InviteKind, InviteResponse},
9        slot::EquipSlot,
10    },
11    generation::{EntityInfo, SpecialEntity},
12    interaction::Interaction,
13    lottery::LootSpec,
14    mounting::VolumePos,
15    outcome::Outcome,
16    resources::{BattleMode, Secs},
17    rtsim::{self, RtSimEntity},
18    terrain::SpriteKind,
19    trade::{TradeAction, TradeId},
20    uid::Uid,
21    util::Dir,
22};
23use serde::{Deserialize, Serialize};
24use specs::Entity as EcsEntity;
25use std::{collections::VecDeque, sync::Mutex};
26use uuid::Uuid;
27use vek::*;
28
29pub type SiteId = u64;
30/// Plugin identifier (sha256)
31pub type PluginHash = [u8; 32];
32
33pub enum LocalEvent {
34    /// Applies upward force to entity's `Vel`
35    Jump(EcsEntity, f32),
36    /// Applies the `impulse` to `entity`'s `Vel`
37    ApplyImpulse {
38        entity: EcsEntity,
39        impulse: Vec3<f32>,
40    },
41    /// Applies `vel` velocity to `entity`
42    Boost { entity: EcsEntity, vel: Vec3<f32> },
43    /// Creates an outcome
44    CreateOutcome(Outcome),
45}
46
47#[derive(Clone, Debug, Default, Deserialize, Serialize)]
48pub struct UpdateCharacterMetadata {
49    pub skill_set_persistence_load_error: Option<comp::skillset::SkillsPersistenceError>,
50}
51
52pub struct NpcBuilder {
53    pub stats: comp::Stats,
54    pub skill_set: comp::SkillSet,
55    pub health: Option<comp::Health>,
56    pub poise: comp::Poise,
57    pub inventory: comp::inventory::Inventory,
58    pub body: comp::Body,
59    pub agent: Option<comp::Agent>,
60    pub alignment: comp::Alignment,
61    pub scale: comp::Scale,
62    pub anchor: Option<comp::Anchor>,
63    pub loot: LootSpec<String>,
64    pub pets: Vec<(NpcBuilder, Vec3<f32>)>,
65    pub rtsim_entity: Option<RtSimEntity>,
66    pub projectile: Option<comp::Projectile>,
67    pub heads: Option<comp::body::parts::Heads>,
68    pub death_effects: Option<DeathEffects>,
69    pub rider_effects: Option<RiderEffects>,
70    pub rider: Option<Box<Self>>,
71}
72
73impl NpcBuilder {
74    pub fn new(stats: comp::Stats, body: comp::Body, alignment: comp::Alignment) -> Self {
75        Self {
76            stats,
77            skill_set: comp::SkillSet::default(),
78            health: None,
79            poise: comp::Poise::new(body),
80            inventory: comp::Inventory::with_empty(),
81            body,
82            agent: None,
83            alignment,
84            scale: comp::Scale(1.0),
85            anchor: None,
86            loot: LootSpec::Nothing,
87            rtsim_entity: None,
88            projectile: None,
89            pets: Vec::new(),
90            heads: None,
91            death_effects: None,
92            rider_effects: None,
93            rider: None,
94        }
95    }
96
97    pub fn with_rider(mut self, rider: impl Into<Option<NpcBuilder>>) -> Self {
98        let rider: Option<NpcBuilder> = rider.into();
99        self.rider = rider.map(Box::new);
100        self
101    }
102
103    pub fn with_heads(mut self, heads: impl Into<Option<comp::body::parts::Heads>>) -> Self {
104        self.heads = heads.into();
105        self
106    }
107
108    pub fn with_health(mut self, health: impl Into<Option<comp::Health>>) -> Self {
109        self.health = health.into();
110        self
111    }
112
113    pub fn with_poise(mut self, poise: comp::Poise) -> Self {
114        self.poise = poise;
115        self
116    }
117
118    pub fn with_agent(mut self, agent: impl Into<Option<comp::Agent>>) -> Self {
119        self.agent = agent.into();
120        self
121    }
122
123    pub fn with_anchor(mut self, anchor: comp::Anchor) -> Self {
124        self.anchor = Some(anchor);
125        self
126    }
127
128    pub fn with_rtsim(mut self, rtsim: RtSimEntity) -> Self {
129        self.rtsim_entity = Some(rtsim);
130        self
131    }
132
133    pub fn with_projectile(mut self, projectile: impl Into<Option<comp::Projectile>>) -> Self {
134        self.projectile = projectile.into();
135        self
136    }
137
138    pub fn with_scale(mut self, scale: comp::Scale) -> Self {
139        self.scale = scale;
140        self
141    }
142
143    pub fn with_inventory(mut self, inventory: comp::Inventory) -> Self {
144        self.inventory = inventory;
145        self
146    }
147
148    pub fn with_skill_set(mut self, skill_set: comp::SkillSet) -> Self {
149        self.skill_set = skill_set;
150        self
151    }
152
153    pub fn with_loot(mut self, loot: LootSpec<String>) -> Self {
154        self.loot = loot;
155        self
156    }
157
158    pub fn with_pets(mut self, pets: Vec<(NpcBuilder, Vec3<f32>)>) -> Self {
159        self.pets = pets;
160        self
161    }
162
163    pub fn with_death_effects(mut self, death_effects: Option<DeathEffects>) -> Self {
164        self.death_effects = death_effects;
165        self
166    }
167
168    pub fn with_rider_effects(mut self, rider_effects: Option<RiderEffects>) -> Self {
169        self.rider_effects = rider_effects;
170        self
171    }
172}
173
174// These events are generated only by server systems
175//
176// TODO: we may want to move these into the server crate, this may allow moving
177// other types out of `common` and would also narrow down where we know specific
178// events will be emitted (if done it should probably be setup so they can
179// easily be moved back here if needed).
180
181pub struct ClientDisconnectEvent(pub EcsEntity, pub DisconnectReason);
182
183pub struct ClientDisconnectWithoutPersistenceEvent(pub EcsEntity);
184
185pub struct CommandEvent(pub EcsEntity, pub String, pub Vec<String>);
186
187pub struct CreateSpecialEntityEvent {
188    pub pos: Vec3<f32>,
189    pub entity: SpecialEntity,
190}
191
192pub struct CreateShipEvent {
193    pub pos: Pos,
194    pub ori: Ori,
195    pub ship: comp::ship::Body,
196    pub rtsim_entity: Option<RtSimEntity>,
197    pub driver: Option<NpcBuilder>,
198}
199
200pub struct CreateItemDropEvent {
201    pub pos: Pos,
202    pub vel: Vel,
203    pub ori: Ori,
204    pub item: comp::PickupItem,
205    pub loot_owner: Option<LootOwner>,
206}
207pub struct CreateObjectEvent {
208    pub pos: Pos,
209    pub vel: Vel,
210    pub body: comp::object::Body,
211    pub object: Option<comp::Object>,
212    pub item: Option<comp::PickupItem>,
213    pub light_emitter: Option<comp::LightEmitter>,
214    pub stats: Option<comp::Stats>,
215}
216
217/// Inserts default components for a character when loading into the game.
218pub struct InitializeCharacterEvent {
219    pub entity: EcsEntity,
220    pub character_id: CharacterId,
221    pub requested_view_distances: crate::ViewDistances,
222}
223
224pub struct InitializeSpectatorEvent(pub EcsEntity, pub crate::ViewDistances);
225
226pub struct UpdateCharacterDataEvent {
227    pub entity: EcsEntity,
228    pub components: (
229        comp::Body,
230        Option<comp::Hardcore>,
231        comp::Stats,
232        comp::SkillSet,
233        comp::Inventory,
234        Option<comp::Waypoint>,
235        Vec<(comp::Pet, comp::Body, comp::Stats)>,
236        comp::ActiveAbilities,
237        Option<comp::MapMarker>,
238    ),
239    pub metadata: UpdateCharacterMetadata,
240}
241
242pub struct ExitIngameEvent {
243    pub entity: EcsEntity,
244}
245
246pub struct RequestSiteInfoEvent {
247    pub entity: EcsEntity,
248    pub id: SiteId,
249}
250
251pub struct TamePetEvent {
252    pub pet_entity: EcsEntity,
253    pub owner_entity: EcsEntity,
254}
255
256pub struct UpdateMapMarkerEvent {
257    pub entity: EcsEntity,
258    pub update: comp::MapMarkerChange,
259}
260
261pub struct MakeAdminEvent {
262    pub entity: EcsEntity,
263    pub admin: comp::Admin,
264    pub uuid: Uuid,
265}
266
267pub struct DeleteCharacterEvent {
268    pub entity: EcsEntity,
269    pub requesting_player_uuid: String,
270    pub character_id: CharacterId,
271}
272
273pub struct TeleportToPositionEvent {
274    pub entity: EcsEntity,
275    pub position: Vec3<f32>,
276}
277
278pub struct RequestPluginsEvent {
279    pub entity: EcsEntity,
280    pub plugins: Vec<PluginHash>,
281}
282
283pub struct SetBattleModeEvent {
284    pub entity: EcsEntity,
285    pub battle_mode: BattleMode,
286}
287
288// These events are generated in common systems in addition to server systems
289// (but note on the client the event buses aren't registered and these events
290// aren't actually emitted).
291
292pub struct ChatEvent {
293    pub msg: UnresolvedChatMsg,
294    // We warn when the server tries to generate non plain `Content` messags
295    // that appear from a player since we currently filter those out.
296    //
297    // But we don't want to spam warnings if this is from a client, so track that here.
298    pub from_client: bool,
299}
300
301pub struct CreateNpcEvent {
302    pub pos: Pos,
303    pub ori: Ori,
304    pub npc: NpcBuilder,
305}
306
307pub struct CreateAuraEntityEvent {
308    pub auras: comp::Auras,
309    pub pos: Pos,
310    pub creator_uid: Uid,
311    pub duration: Option<Secs>,
312}
313
314pub struct ExplosionEvent {
315    pub pos: Vec3<f32>,
316    pub explosion: Explosion,
317    pub owner: Option<Uid>,
318}
319
320pub struct BonkEvent {
321    pub pos: Vec3<f32>,
322    pub owner: Option<Uid>,
323    pub target: Option<Uid>,
324}
325
326pub struct HealthChangeEvent {
327    pub entity: EcsEntity,
328    pub change: comp::HealthChange,
329}
330
331pub struct KillEvent {
332    pub entity: EcsEntity,
333}
334
335pub struct HelpDownedEvent {
336    pub helper: Option<Uid>,
337    pub target: Uid,
338}
339
340pub struct DownedEvent {
341    pub entity: EcsEntity,
342}
343
344pub struct PoiseChangeEvent {
345    pub entity: EcsEntity,
346    pub change: comp::PoiseChange,
347}
348
349pub struct DeleteEvent(pub EcsEntity);
350
351pub struct DestroyEvent {
352    pub entity: EcsEntity,
353    pub cause: comp::HealthChange,
354}
355
356pub struct InventoryManipEvent(pub EcsEntity, pub comp::InventoryManip);
357
358pub struct GroupManipEvent(pub EcsEntity, pub comp::GroupManip);
359
360pub struct RespawnEvent(pub EcsEntity);
361
362pub struct ShootEvent {
363    pub entity: Option<EcsEntity>,
364    pub pos: Pos,
365    pub dir: Dir,
366    pub body: comp::Body,
367    pub light: Option<comp::LightEmitter>,
368    pub projectile: comp::Projectile,
369    pub speed: f32,
370    pub object: Option<comp::Object>,
371}
372
373pub struct ThrowEvent {
374    pub entity: EcsEntity,
375    pub pos: Pos,
376    pub dir: Dir,
377    pub light: Option<comp::LightEmitter>,
378    pub projectile: comp::Projectile,
379    pub speed: f32,
380    pub object: Option<comp::Object>,
381    pub equip_slot: EquipSlot,
382}
383
384pub struct ShockwaveEvent {
385    pub properties: comp::shockwave::Properties,
386    pub pos: Pos,
387    pub ori: Ori,
388}
389
390pub struct KnockbackEvent {
391    pub entity: EcsEntity,
392    pub impulse: Vec3<f32>,
393}
394
395pub struct LandOnGroundEvent {
396    pub entity: EcsEntity,
397    pub vel: Vec3<f32>,
398    pub surface_normal: Vec3<f32>,
399}
400
401pub struct SetLanternEvent(pub EcsEntity, pub bool);
402
403pub struct NpcInteractEvent(pub EcsEntity, pub EcsEntity);
404
405pub struct DialogueEvent(pub EcsEntity, pub EcsEntity, pub rtsim::Dialogue);
406
407pub struct InviteResponseEvent(pub EcsEntity, pub InviteResponse);
408
409pub struct InitiateInviteEvent(pub EcsEntity, pub Uid, pub InviteKind);
410
411pub struct ProcessTradeActionEvent(pub EcsEntity, pub TradeId, pub TradeAction);
412
413pub enum MountEvent {
414    MountEntity(EcsEntity, EcsEntity),
415    MountVolume(EcsEntity, VolumePos),
416    Unmount(EcsEntity),
417}
418
419pub struct SetPetStayEvent(pub EcsEntity, pub EcsEntity, pub bool);
420
421pub struct PossessEvent(pub Uid, pub Uid);
422
423pub struct TransformEvent {
424    pub target_entity: Uid,
425    pub entity_info: EntityInfo,
426    /// If set to false, players wont be transformed unless with a Possessor
427    /// presence kind
428    pub allow_players: bool,
429    /// Whether the entity should be deleted if transforming fails (only applies
430    /// to non-players)
431    pub delete_on_failure: bool,
432}
433
434pub struct StartInteractionEvent(pub Interaction);
435
436pub struct AuraEvent {
437    pub entity: EcsEntity,
438    pub aura_change: comp::AuraChange,
439}
440
441pub struct BuffEvent {
442    pub entity: EcsEntity,
443    pub buff_change: comp::BuffChange,
444}
445
446pub struct EnergyChangeEvent {
447    pub entity: EcsEntity,
448    pub change: f32,
449    pub reset_rate: bool,
450}
451
452pub struct ComboChangeEvent {
453    pub entity: EcsEntity,
454    pub change: i32,
455}
456
457pub struct ParryHookEvent {
458    pub defender: EcsEntity,
459    pub attacker: Option<EcsEntity>,
460    pub source: AttackSource,
461    pub poise_multiplier: f32,
462}
463
464/// Attempt to mine a block, turning it into an item.
465pub struct MineBlockEvent {
466    pub entity: EcsEntity,
467    pub pos: Vec3<i32>,
468    pub tool: Option<comp::tool::ToolKind>,
469}
470
471pub struct TeleportToEvent {
472    pub entity: EcsEntity,
473    pub target: Uid,
474    pub max_range: Option<f32>,
475}
476
477pub struct SoundEvent {
478    pub sound: Sound,
479}
480
481pub struct CreateSpriteEvent {
482    pub pos: Vec3<i32>,
483    pub sprite: SpriteKind,
484    pub del_timeout: Option<(f32, f32)>,
485}
486
487pub struct EntityAttackedHookEvent {
488    pub entity: EcsEntity,
489    pub attacker: Option<EcsEntity>,
490}
491
492pub struct ChangeAbilityEvent {
493    pub entity: EcsEntity,
494    pub slot: usize,
495    pub auxiliary_key: comp::ability::AuxiliaryKey,
496    pub new_ability: comp::ability::AuxiliaryAbility,
497}
498
499pub struct ChangeStanceEvent {
500    pub entity: EcsEntity,
501    pub stance: comp::Stance,
502}
503
504pub struct PermanentChange {
505    pub expected_old_body: comp::Body,
506}
507
508pub struct ChangeBodyEvent {
509    pub entity: EcsEntity,
510    pub new_body: comp::Body,
511    /// Is Some if this change should be persisted.
512    ///
513    /// Only applies to player characters.
514    pub permanent_change: Option<PermanentChange>,
515}
516
517pub struct RemoveLightEmitterEvent {
518    pub entity: EcsEntity,
519}
520
521pub struct StartTeleportingEvent {
522    pub entity: EcsEntity,
523    pub portal: EcsEntity,
524}
525
526pub struct ToggleSpriteLightEvent {
527    pub entity: EcsEntity,
528    pub pos: Vec3<i32>,
529    pub enable: bool,
530}
531
532pub struct RegrowHeadEvent {
533    pub entity: EcsEntity,
534}
535
536struct EventBusInner<E> {
537    queue: VecDeque<E>,
538    /// Saturates to u8::MAX and is never reset.
539    ///
540    /// Used in the first tick to check for if certain event types are handled
541    /// and only handled once.
542    #[cfg(debug_assertions)]
543    recv_count: u8,
544}
545
546pub struct EventBus<E> {
547    inner: Mutex<EventBusInner<E>>,
548}
549
550impl<E> Default for EventBus<E> {
551    fn default() -> Self {
552        Self {
553            inner: Mutex::new(EventBusInner {
554                queue: VecDeque::new(),
555                #[cfg(debug_assertions)]
556                recv_count: 0,
557            }),
558        }
559    }
560}
561
562impl<E> EventBus<E> {
563    pub fn emitter(&self) -> Emitter<E> {
564        Emitter {
565            bus: self,
566            events: VecDeque::new(),
567        }
568    }
569
570    pub fn emit_now(&self, event: E) {
571        self.inner.lock().expect("Poisoned").queue.push_back(event);
572    }
573
574    pub fn recv_all(&self) -> impl ExactSizeIterator<Item = E> + use<E> {
575        {
576            let mut guard = self.inner.lock().expect("Poisoned");
577            #[cfg(debug_assertions)]
578            {
579                guard.recv_count = guard.recv_count.saturating_add(1);
580            }
581            core::mem::take(&mut guard.queue)
582        }
583        .into_iter()
584    }
585
586    pub fn recv_all_mut(&mut self) -> impl ExactSizeIterator<Item = E> + use<E> {
587        let inner = self.inner.get_mut().expect("Poisoned");
588        #[cfg(debug_assertions)]
589        {
590            inner.recv_count = inner.recv_count.saturating_add(1);
591        }
592        core::mem::take(&mut inner.queue).into_iter()
593    }
594
595    #[cfg(debug_assertions)]
596    pub fn recv_count(&mut self) -> u8 { self.inner.get_mut().expect("Poisoned").recv_count }
597}
598
599pub struct Emitter<'a, E> {
600    bus: &'a EventBus<E>,
601    pub events: VecDeque<E>,
602}
603
604impl<E> Emitter<'_, E> {
605    pub fn emit(&mut self, event: E) { self.events.push_back(event); }
606
607    pub fn emit_many(&mut self, events: impl IntoIterator<Item = E>) { self.events.extend(events); }
608
609    pub fn append(&mut self, other: &mut VecDeque<E>) { self.events.append(other) }
610
611    pub fn append_vec(&mut self, vec: Vec<E>) {
612        if self.events.is_empty() {
613            self.events = vec.into();
614        } else {
615            self.events.extend(vec);
616        }
617    }
618}
619
620impl<E> Drop for Emitter<'_, E> {
621    fn drop(&mut self) {
622        if !self.events.is_empty() {
623            let mut guard = self.bus.inner.lock().expect("Poision");
624            guard.queue.append(&mut self.events);
625        }
626    }
627}
628
629pub trait EmitExt<E> {
630    fn emit(&mut self, event: E);
631    fn emit_many(&mut self, events: impl IntoIterator<Item = E>);
632}
633
634/// Define ecs read data for event busses. And a way to convert them all to
635/// emitters.
636///
637/// # Example:
638/// ```
639/// mod some_mod_is_necessary_for_the_test {
640///     use veloren_common::event_emitters;
641///     pub struct Foo;
642///     pub struct Bar;
643///     pub struct Baz;
644///     event_emitters!(
645///       pub struct ReadEvents[EventEmitters] {
646///           foo: Foo, bar: Bar, baz: Baz,
647///       }
648///     );
649/// }
650/// ```
651#[macro_export]
652macro_rules! event_emitters {
653    ($($vis:vis struct $read_data:ident[$emitters:ident] { $($ev_ident:ident: $ty:ty),+ $(,)? })+) => {
654        mod event_emitters {
655            use super::*;
656            use specs::shred;
657            $(
658            #[derive(specs::SystemData)]
659            pub struct $read_data<'a> {
660                $($ev_ident: Option<specs::Read<'a, $crate::event::EventBus<$ty>>>),+
661            }
662
663            impl<'a> $read_data<'a> {
664                pub fn get_emitters(&self) -> $emitters {
665                    $emitters {
666                        $($ev_ident: self.$ev_ident.as_ref().map(|e| e.emitter())),+
667                    }
668                }
669            }
670
671            pub struct $emitters<'a> {
672                $($ev_ident: Option<$crate::event::Emitter<'a, $ty>>),+
673            }
674
675            impl<'a> $emitters<'a> {
676                #[expect(unused)]
677                pub fn append(&mut self, mut other: Self) {
678                    $(
679                        self.$ev_ident.as_mut().zip(other.$ev_ident).map(|(a, mut b)| a.append(&mut b.events));
680                    )+
681                }
682            }
683
684            $(
685                impl<'a> $crate::event::EmitExt<$ty> for $emitters<'a> {
686                    fn emit(&mut self, event: $ty) { self.$ev_ident.as_mut().map(|e| e.emit(event)); }
687                    fn emit_many(&mut self, events: impl IntoIterator<Item = $ty>) { self.$ev_ident.as_mut().map(|e| e.emit_many(events)); }
688                }
689            )+
690            )+
691        }
692        $(
693            $vis use event_emitters::{$read_data, $emitters};
694        )+
695    }
696}