1use crate::{persistence::character_updater, sys::SysScheduler};
2use common::{
3 comp::{
4 ActiveAbilities, Alignment, Body, Inventory, MapMarker, Presence, PresenceKind, SkillSet,
5 Stats, Waypoint,
6 pet::{Pet, is_tameable},
7 },
8 uid::Uid,
9};
10use common_ecs::{Job, Origin, Phase, System};
11use specs::{Join, LendJoin, ReadStorage, Write, WriteExpect};
12use tracing::error;
13
14#[derive(Default)]
15pub struct Sys;
16
17impl<'a> System<'a> for Sys {
18 type SystemData = (
19 ReadStorage<'a, Alignment>,
20 ReadStorage<'a, Body>,
21 ReadStorage<'a, Presence>,
22 ReadStorage<'a, SkillSet>,
23 ReadStorage<'a, Inventory>,
24 ReadStorage<'a, Uid>,
25 ReadStorage<'a, Waypoint>,
26 ReadStorage<'a, MapMarker>,
27 ReadStorage<'a, Pet>,
28 ReadStorage<'a, Stats>,
29 ReadStorage<'a, ActiveAbilities>,
30 WriteExpect<'a, character_updater::CharacterUpdater>,
31 Write<'a, SysScheduler<Self>>,
32 );
33
34 const NAME: &'static str = "persistence";
35 const ORIGIN: Origin = Origin::Server;
36 const PHASE: Phase = Phase::Create;
37
38 fn run(
39 _job: &mut Job<Self>,
40 (
41 alignments,
42 bodies,
43 presences,
44 player_skill_set,
45 player_inventories,
46 uids,
47 player_waypoints,
48 map_markers,
49 pets,
50 stats,
51 active_abilities,
52 mut updater,
53 mut scheduler,
54 ): Self::SystemData,
55 ) {
56 if scheduler.should_run() {
57 updater.batch_update(
58 (
59 &presences,
60 &player_skill_set,
61 &player_inventories,
62 &uids,
63 player_waypoints.maybe(),
64 &active_abilities,
65 map_markers.maybe(),
66 )
67 .join()
68 .filter_map(
69 |(
70 presence,
71 skill_set,
72 inventory,
73 player_uid,
74 waypoint,
75 active_abilities,
76 map_marker,
77 )| match presence.kind {
78 PresenceKind::LoadingCharacter(_char_id) => {
79 error!(
80 "Unexpected state when persisting characters! Some of the \
81 components required above should only be present after a \
82 character is loaded!"
83 );
84 None
85 },
86 PresenceKind::Character(id) => {
87 let pets = (&alignments, &bodies, &stats, &pets)
88 .join()
89 .filter_map(|(alignment, body, stats, pet)| match alignment {
90 Alignment::Owned(ref pet_owner)
94 if pet_owner == player_uid && is_tameable(body) =>
95 {
96 Some(((*pet).clone(), *body, stats.clone()))
97 },
98 _ => None,
99 })
100 .collect();
101
102 Some((
103 id,
104 skill_set.clone(),
105 inventory.clone(),
106 pets,
107 waypoint.cloned(),
108 active_abilities.clone(),
109 map_marker.cloned(),
110 ))
111 },
112 PresenceKind::Spectator | PresenceKind::Possessor => None,
113 },
114 ),
115 );
116 }
117 }
118}