veloren_common/
event.rs

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