rig_ecs/checkpoint/
restore.rs1use std::collections::{BTreeMap, HashSet};
12
13use bevy_ecs::prelude::*;
14use bevy_reflect::TypePath;
15use rig_core::{
16 effect::{HandlerDescriptor, HandlerKey},
17 serve::ErasedHandler,
18};
19
20use super::{Checkpoint, CheckpointError, Loaded};
21use crate::bus::{Bound, HandlerIndex, handlers::HandlerTable};
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum RestoreMode {
26 Strict,
33 Replace,
37}
38
39impl Checkpoint {
40 pub fn requirements(&self) -> Result<Vec<HandlerDescriptor>, CheckpointError> {
44 let mut keys = HashSet::new();
45 let mut requirements = Vec::new();
46 for (row, entity) in self.entities.iter().enumerate() {
47 if let Some(value) = entity.get(Bound::type_path()) {
48 let bound = super::saved_bound(row, value)?;
49 if bound.key != bound.descriptor.key {
50 return Err(CheckpointError::HandlerKeyMismatch { key: bound.key });
51 }
52 if !keys.insert(bound.key.clone()) {
53 return Err(CheckpointError::DuplicateSavedHandler { key: bound.key });
54 }
55 requirements.push(bound.descriptor);
56 }
57 }
58 requirements.sort_by(|a, b| a.key.cmp(&b.key));
59 Ok(requirements)
60 }
61}
62
63pub fn load_world(
79 checkpoint: &Checkpoint,
80 world: &mut World,
81 mode: RestoreMode,
82 handlers: impl IntoIterator<Item = (HandlerKey, ErasedHandler)>,
83) -> Result<Loaded, CheckpointError> {
84 let requirements = checkpoint.requirements()?;
85 let (assets, aliases) = super::validated_state(checkpoint, world)?;
86 let mut supplied = BTreeMap::new();
87 for (key, handler) in handlers {
88 if supplied.insert(key.clone(), handler).is_some() {
89 return Err(CheckpointError::DuplicateSuppliedHandler { key });
90 }
91 }
92 let index = world
93 .get_resource::<HandlerIndex>()
94 .ok_or(CheckpointError::NotInstalled("handler index"))?;
95 let table = world
96 .get_non_send::<HandlerTable>()
97 .ok_or(CheckpointError::NotInstalled("handler table"))?;
98 let mut descriptors = BTreeMap::new();
99 for saved in &requirements {
100 let actual = if let Some(handler) = supplied.get(&saved.key) {
101 let mut descriptor = handler.descriptor();
102 descriptor.key = saved.key.clone();
103 descriptor
104 } else {
105 index
106 .entity(&saved.key)
107 .filter(|entity| table.contains(*entity))
108 .and_then(|entity| world.get::<Bound>(entity))
109 .ok_or_else(|| CheckpointError::MissingHandler {
110 key: saved.key.clone(),
111 })?
112 .descriptor
113 .clone()
114 };
115 if actual.family.family() != saved.family.family() {
116 return Err(CheckpointError::FamilyChanged {
117 key: saved.key.clone(),
118 saved: saved.family.family(),
119 found: actual.family.family(),
120 });
121 }
122 if mode == RestoreMode::Strict && actual != *saved {
123 return Err(CheckpointError::DescriptorChanged {
124 key: saved.key.clone(),
125 });
126 }
127 descriptors.insert(saved.key.clone(), actual);
128 }
129 for key in supplied.keys() {
130 if !descriptors.contains_key(key) {
131 return Err(CheckpointError::UnrequiredHandler { key: key.clone() });
132 }
133 }
134
135 let loaded = super::load_state(checkpoint, world, assets, aliases)?;
136 for entity in &loaded.entities {
137 let Some(bound) = world.get::<Bound>(*entity) else {
138 continue;
139 };
140 let key = bound.key.clone();
141 if let Some(descriptor) = descriptors.remove(&key) {
143 world.entity_mut(*entity).insert(Bound {
144 key: key.clone(),
145 descriptor,
146 });
147 }
148 if let Some(handler) = supplied.remove(&key) {
149 HandlerTable::install(world, *entity, handler);
150 }
151 }
152 Ok(loaded)
153}