steel_core/chunk_saver/storage/
light.rs1use super::{
2 ChunkLightData, ChunkLightLayerStorage, ChunkStatus, ChunkStorage, DATA_LAYER_SIZE,
3 LightSection, LightSectionData, PersistentLightData, PersistentLightSection,
4 homogeneous_packed_light_value,
5};
6
7impl ChunkStorage {
8 pub(super) fn light_to_persistent(light: &ChunkLightData) -> PersistentLightData {
10 PersistentLightData {
11 block: Self::light_layer_to_persistent(&light.block),
12 sky: Self::light_layer_to_persistent(&light.sky),
13 }
14 }
15
16 pub(super) fn light_layer_to_persistent(
17 layer: &ChunkLightLayerStorage,
18 ) -> Vec<PersistentLightSection> {
19 layer
20 .sections()
21 .iter()
22 .enumerate()
23 .filter_map(|(index, section)| {
24 let Ok(section_index) = u32::try_from(index) else {
25 tracing::warn!(
26 index,
27 "Light section index does not fit in persistent format"
28 );
29 return None;
30 };
31
32 match section {
33 LightSection::Missing => None,
34 LightSection::Visible(data) => {
35 if data.is_all_zero() {
36 Some(PersistentLightSection::Uninitialized { section_index })
37 } else {
38 Some(PersistentLightSection::Initialized {
39 section_index,
40 data: data.to_bytes().as_ref().to_vec(),
41 })
42 }
43 }
44 LightSection::Internal(data) => {
45 if data.is_all_zero() {
46 None
47 } else {
48 Some(PersistentLightSection::Internal {
49 section_index,
50 data: data.to_bytes().as_ref().to_vec(),
51 })
52 }
53 }
54 }
55 })
56 .collect()
57 }
58
59 pub(super) fn persistent_to_light(
60 persistent: &PersistentLightData,
61 min_y: i32,
62 height: i32,
63 status: ChunkStatus,
64 ) -> ChunkLightData {
65 let mut light = ChunkLightData::for_valid_world_height(min_y, height);
66 if status < ChunkStatus::Light {
67 return light;
68 }
69
70 Self::apply_persistent_light_layer(&mut light.block, &persistent.block, "block");
71 Self::apply_persistent_light_layer(&mut light.sky, &persistent.sky, "sky");
72 light
73 .sky
74 .fill_loaded_missing_sky_sections_below_data_with_zero();
75 light
76 }
77
78 pub(super) fn apply_persistent_light_layer(
79 layer: &mut ChunkLightLayerStorage,
80 persistent: &[PersistentLightSection],
81 layer_name: &str,
82 ) {
83 for section in persistent {
84 let Ok(section_index) = usize::try_from(section.section_index()) else {
85 tracing::warn!(
86 layer = layer_name,
87 section_index = section.section_index(),
88 "Persisted light section index does not fit this platform"
89 );
90 continue;
91 };
92
93 let Some(target) = layer.sections_mut().get_mut(section_index) else {
94 tracing::warn!(
95 layer = layer_name,
96 section_index,
97 "Persisted light section index is outside world light range"
98 );
99 continue;
100 };
101
102 let Some(restored) = Self::persistent_to_light_section(section, layer_name) else {
103 continue;
104 };
105 *target = restored;
106 }
107 }
108
109 pub(super) fn persistent_to_light_section(
110 persistent: &PersistentLightSection,
111 layer_name: &str,
112 ) -> Option<LightSection> {
113 match persistent {
114 PersistentLightSection::Uninitialized { .. } => {
115 Some(LightSection::visible(LightSectionData::homogeneous(0)))
116 }
117 PersistentLightSection::Initialized {
118 section_index,
119 data,
120 } => Self::persistent_light_bytes_to_data(data, *section_index, layer_name)
121 .map(LightSection::visible),
122 PersistentLightSection::Internal {
123 section_index,
124 data,
125 } => {
126 let restored =
127 Self::persistent_light_bytes_to_data(data, *section_index, layer_name)?;
128 if restored.is_all_zero() {
129 None
130 } else {
131 Some(LightSection::internal(restored))
132 }
133 }
134 }
135 }
136
137 pub(super) fn persistent_light_bytes_to_data(
138 data: &[u8],
139 section_index: u32,
140 layer_name: &str,
141 ) -> Option<LightSectionData> {
142 let actual = data.len();
143 let bytes = Box::<[u8]>::from(data);
144 let result: Result<Box<[u8; DATA_LAYER_SIZE]>, Box<[u8]>> = bytes.try_into();
145 let Ok(bytes) = result else {
146 tracing::warn!(
147 layer = layer_name,
148 section_index,
149 actual,
150 expected = DATA_LAYER_SIZE,
151 "Skipping persisted light section with invalid byte length"
152 );
153 return None;
154 };
155
156 if let Some(value) = homogeneous_packed_light_value(&bytes) {
157 Some(LightSectionData::homogeneous(value))
158 } else {
159 Some(LightSectionData::Packed(bytes))
160 }
161 }
162}