Skip to main content

steel_core/chunk_saver/storage/
structures.rs

1use super::{
2    BlockPos, ChunkPos, ChunkStorage, DesertPyramidPieceData, FortressPieceData, IVec3,
3    JigsawJunction, JigsawPieceData, JungleTemplePieceData, MineshaftPieceKind,
4    MineshaftPiecePayload, OceanMonumentChildPiece, OceanMonumentChildPieceKind,
5    OceanMonumentPieceData, OceanMonumentRoomData, PackedChunkPos, PersistentBoundingBox,
6    PersistentDesertPyramidPieceData, PersistentJigsawJunction, PersistentJigsawPieceData,
7    PersistentJungleTemplePieceData, PersistentMineshaftPieceData, PersistentMineshaftPieceKind,
8    PersistentNetherFortressPieceData, PersistentOceanMonumentChildPiece,
9    PersistentOceanMonumentChildPieceKind, PersistentOceanMonumentPieceData,
10    PersistentOceanMonumentRoomData, PersistentPoolElement, PersistentProceduralPieceData,
11    PersistentProcessorList, PersistentStrongholdPieceData, PersistentStrongholdSmallDoorType,
12    PersistentStructurePiece, PersistentStructurePiecePayload, PersistentStructureReference,
13    PersistentStructureStart, PersistentSwampHutPieceData, PersistentTemplatePieceData,
14    PersistentTemplateProcessorList, PoolElement, ProceduralPieceData, ProcessorList, REGISTRY,
15    RegistryExt, RuinedPortalProperties, StrongholdPieceData, StrongholdSmallDoorType,
16    StructurePiece, StructurePiecePayload, StructureReferenceMap, StructureStart,
17    StructureStartMap, SwampHutPieceData, TemplatePieceData, TemplateProcessorList,
18    TerrainAdjustment, block_ignore_from_persistent, block_ignore_to_persistent,
19    compare_identifiers, direction_from_2d, direction_to_2d, liquid_settings_from_persistent,
20    liquid_settings_to_persistent, marker_handling_from_persistent, marker_handling_to_persistent,
21    mineshaft_type_from_persistent, mineshaft_type_to_persistent, mirror_from_persistent,
22    mirror_to_persistent, ocean_ruin_biome_temp_from_persistent,
23    ocean_ruin_biome_temp_to_persistent, placement_adjustment_from_persistent,
24    placement_adjustment_to_persistent, placement_clip_from_persistent,
25    placement_clip_to_persistent, post_process_from_persistent, post_process_to_persistent,
26    projection_from_persistent, projection_to_persistent, required_direction_from_2d,
27    required_projection_from_persistent, rotation_from_persistent, rotation_to_persistent,
28    ruined_portal_placement_from_persistent, ruined_portal_placement_to_persistent,
29};
30
31impl ChunkStorage {
32    pub(super) fn jigsaw_piece_data_to_persistent(
33        data: &JigsawPieceData,
34    ) -> PersistentJigsawPieceData {
35        PersistentJigsawPieceData {
36            pool_element: Self::pool_element_to_persistent(&data.pool_element),
37            position: [data.position.x, data.position.y, data.position.z],
38            rotation: rotation_to_persistent(data.rotation),
39            liquid_settings: liquid_settings_to_persistent(data.liquid_settings),
40        }
41    }
42
43    pub(super) fn persistent_to_jigsaw_piece_data(
44        data: &PersistentJigsawPieceData,
45    ) -> JigsawPieceData {
46        JigsawPieceData {
47            pool_element: Self::persistent_to_pool_element(&data.pool_element),
48            position: IVec3::new(data.position[0], data.position[1], data.position[2]),
49            rotation: rotation_from_persistent(data.rotation),
50            liquid_settings: liquid_settings_from_persistent(data.liquid_settings),
51        }
52    }
53
54    pub(super) fn procedural_piece_data_to_persistent(
55        data: &ProceduralPieceData,
56    ) -> PersistentProceduralPieceData {
57        match data {
58            ProceduralPieceData::Unimplemented => PersistentProceduralPieceData::Unimplemented,
59            ProceduralPieceData::BuriedTreasure => PersistentProceduralPieceData::BuriedTreasure,
60            ProceduralPieceData::DesertPyramid(data) => {
61                PersistentProceduralPieceData::DesertPyramid(PersistentDesertPyramidPieceData {
62                    height_position: data.height_position.unwrap_or(-1),
63                    has_placed_chest: data.has_placed_chest,
64                })
65            }
66            ProceduralPieceData::JungleTemple(data) => {
67                PersistentProceduralPieceData::JungleTemple(PersistentJungleTemplePieceData {
68                    height_position: data.height_position.unwrap_or(-1),
69                    placed_main_chest: data.placed_main_chest,
70                    placed_hidden_chest: data.placed_hidden_chest,
71                    placed_trap1: data.placed_trap1,
72                    placed_trap2: data.placed_trap2,
73                })
74            }
75            ProceduralPieceData::Mineshaft(data) => {
76                PersistentProceduralPieceData::Mineshaft(PersistentMineshaftPieceData {
77                    mineshaft_type: mineshaft_type_to_persistent(data.mineshaft_type),
78                    kind: Self::mineshaft_kind_to_persistent(&data.kind),
79                })
80            }
81            ProceduralPieceData::NetherFortress(data) => {
82                PersistentProceduralPieceData::NetherFortress(
83                    Self::fortress_piece_data_to_persistent(*data),
84                )
85            }
86            ProceduralPieceData::OceanMonument(data) => {
87                PersistentProceduralPieceData::OceanMonument(
88                    Self::ocean_monument_data_to_persistent(data),
89                )
90            }
91            ProceduralPieceData::Stronghold(data) => PersistentProceduralPieceData::Stronghold(
92                Self::stronghold_piece_data_to_persistent(*data),
93            ),
94            ProceduralPieceData::SwampHut(data) => {
95                PersistentProceduralPieceData::SwampHut(PersistentSwampHutPieceData {
96                    height_position: data.height_position.unwrap_or(-1),
97                    spawned_witch: data.spawned_witch,
98                    spawned_cat: data.spawned_cat,
99                })
100            }
101        }
102    }
103
104    pub(super) fn persistent_to_procedural_piece_data(
105        data: &PersistentProceduralPieceData,
106    ) -> ProceduralPieceData {
107        match data {
108            PersistentProceduralPieceData::Unimplemented => ProceduralPieceData::Unimplemented,
109            PersistentProceduralPieceData::BuriedTreasure => ProceduralPieceData::BuriedTreasure,
110            PersistentProceduralPieceData::DesertPyramid(data) => {
111                ProceduralPieceData::DesertPyramid(DesertPyramidPieceData {
112                    height_position: (data.height_position >= 0).then_some(data.height_position),
113                    has_placed_chest: data.has_placed_chest,
114                    potential_suspicious_sand_world_positions: Vec::new(),
115                    random_collapsed_roof_pos: BlockPos::new(0, 0, 0),
116                })
117            }
118            PersistentProceduralPieceData::JungleTemple(data) => {
119                ProceduralPieceData::JungleTemple(JungleTemplePieceData {
120                    height_position: (data.height_position >= 0).then_some(data.height_position),
121                    placed_main_chest: data.placed_main_chest,
122                    placed_hidden_chest: data.placed_hidden_chest,
123                    placed_trap1: data.placed_trap1,
124                    placed_trap2: data.placed_trap2,
125                })
126            }
127            PersistentProceduralPieceData::Mineshaft(data) => {
128                ProceduralPieceData::Mineshaft(MineshaftPiecePayload {
129                    mineshaft_type: mineshaft_type_from_persistent(data.mineshaft_type),
130                    kind: Self::persistent_to_mineshaft_kind(&data.kind),
131                })
132            }
133            PersistentProceduralPieceData::NetherFortress(data) => {
134                ProceduralPieceData::NetherFortress(Self::persistent_to_fortress_piece_data(data))
135            }
136            PersistentProceduralPieceData::OceanMonument(data) => {
137                ProceduralPieceData::OceanMonument(Self::persistent_to_ocean_monument_data(data))
138            }
139            PersistentProceduralPieceData::Stronghold(data) => {
140                ProceduralPieceData::Stronghold(Self::persistent_to_stronghold_piece_data(data))
141            }
142            PersistentProceduralPieceData::SwampHut(data) => {
143                ProceduralPieceData::SwampHut(SwampHutPieceData {
144                    height_position: (data.height_position >= 0).then_some(data.height_position),
145                    spawned_witch: data.spawned_witch,
146                    spawned_cat: data.spawned_cat,
147                })
148            }
149        }
150    }
151
152    pub(super) fn ocean_monument_data_to_persistent(
153        data: &OceanMonumentPieceData,
154    ) -> PersistentOceanMonumentPieceData {
155        PersistentOceanMonumentPieceData {
156            child_pieces: data
157                .child_pieces
158                .iter()
159                .map(Self::ocean_monument_child_to_persistent)
160                .collect(),
161        }
162    }
163
164    pub(super) fn persistent_to_ocean_monument_data(
165        data: &PersistentOceanMonumentPieceData,
166    ) -> OceanMonumentPieceData {
167        OceanMonumentPieceData {
168            child_pieces: data
169                .child_pieces
170                .iter()
171                .map(Self::persistent_to_ocean_monument_child)
172                .collect(),
173        }
174    }
175
176    const fn ocean_monument_child_to_persistent(
177        child: &OceanMonumentChildPiece,
178    ) -> PersistentOceanMonumentChildPiece {
179        PersistentOceanMonumentChildPiece {
180            bounding_box: PersistentBoundingBox::from_bounding_box(child.bounding_box),
181            kind: Self::ocean_monument_child_kind_to_persistent(&child.kind),
182        }
183    }
184
185    const fn persistent_to_ocean_monument_child(
186        child: &PersistentOceanMonumentChildPiece,
187    ) -> OceanMonumentChildPiece {
188        OceanMonumentChildPiece {
189            bounding_box: child.bounding_box.to_bounding_box(),
190            kind: Self::persistent_to_ocean_monument_child_kind(&child.kind),
191        }
192    }
193
194    const fn ocean_monument_child_kind_to_persistent(
195        kind: &OceanMonumentChildPieceKind,
196    ) -> PersistentOceanMonumentChildPieceKind {
197        match kind {
198            OceanMonumentChildPieceKind::EntryRoom { room } => {
199                PersistentOceanMonumentChildPieceKind::EntryRoom {
200                    room: Self::ocean_monument_room_to_persistent(*room),
201                }
202            }
203            OceanMonumentChildPieceKind::CoreRoom => {
204                PersistentOceanMonumentChildPieceKind::CoreRoom
205            }
206            OceanMonumentChildPieceKind::DoubleXRoom { west, east } => {
207                PersistentOceanMonumentChildPieceKind::DoubleXRoom {
208                    west: Self::ocean_monument_room_to_persistent(*west),
209                    east: Self::ocean_monument_room_to_persistent(*east),
210                }
211            }
212            OceanMonumentChildPieceKind::DoubleXYRoom {
213                west,
214                east,
215                west_up,
216                east_up,
217            } => PersistentOceanMonumentChildPieceKind::DoubleXYRoom {
218                west: Self::ocean_monument_room_to_persistent(*west),
219                east: Self::ocean_monument_room_to_persistent(*east),
220                west_up: Self::ocean_monument_room_to_persistent(*west_up),
221                east_up: Self::ocean_monument_room_to_persistent(*east_up),
222            },
223            OceanMonumentChildPieceKind::DoubleYRoom { room, above } => {
224                PersistentOceanMonumentChildPieceKind::DoubleYRoom {
225                    room: Self::ocean_monument_room_to_persistent(*room),
226                    above: Self::ocean_monument_room_to_persistent(*above),
227                }
228            }
229            OceanMonumentChildPieceKind::DoubleYZRoom {
230                south,
231                north,
232                south_up,
233                north_up,
234            } => PersistentOceanMonumentChildPieceKind::DoubleYZRoom {
235                south: Self::ocean_monument_room_to_persistent(*south),
236                north: Self::ocean_monument_room_to_persistent(*north),
237                south_up: Self::ocean_monument_room_to_persistent(*south_up),
238                north_up: Self::ocean_monument_room_to_persistent(*north_up),
239            },
240            OceanMonumentChildPieceKind::DoubleZRoom { south, north } => {
241                PersistentOceanMonumentChildPieceKind::DoubleZRoom {
242                    south: Self::ocean_monument_room_to_persistent(*south),
243                    north: Self::ocean_monument_room_to_persistent(*north),
244                }
245            }
246            OceanMonumentChildPieceKind::SimpleRoom { room, main_design } => {
247                PersistentOceanMonumentChildPieceKind::SimpleRoom {
248                    room: Self::ocean_monument_room_to_persistent(*room),
249                    main_design: *main_design,
250                }
251            }
252            OceanMonumentChildPieceKind::SimpleTopRoom { room } => {
253                PersistentOceanMonumentChildPieceKind::SimpleTopRoom {
254                    room: Self::ocean_monument_room_to_persistent(*room),
255                }
256            }
257            OceanMonumentChildPieceKind::WingRoom { main_design } => {
258                PersistentOceanMonumentChildPieceKind::WingRoom {
259                    main_design: *main_design,
260                }
261            }
262            OceanMonumentChildPieceKind::Penthouse => {
263                PersistentOceanMonumentChildPieceKind::Penthouse
264            }
265        }
266    }
267
268    const fn persistent_to_ocean_monument_child_kind(
269        kind: &PersistentOceanMonumentChildPieceKind,
270    ) -> OceanMonumentChildPieceKind {
271        match kind {
272            PersistentOceanMonumentChildPieceKind::EntryRoom { room } => {
273                OceanMonumentChildPieceKind::EntryRoom {
274                    room: Self::persistent_to_ocean_monument_room(room),
275                }
276            }
277            PersistentOceanMonumentChildPieceKind::CoreRoom => {
278                OceanMonumentChildPieceKind::CoreRoom
279            }
280            PersistentOceanMonumentChildPieceKind::DoubleXRoom { west, east } => {
281                OceanMonumentChildPieceKind::DoubleXRoom {
282                    west: Self::persistent_to_ocean_monument_room(west),
283                    east: Self::persistent_to_ocean_monument_room(east),
284                }
285            }
286            PersistentOceanMonumentChildPieceKind::DoubleXYRoom {
287                west,
288                east,
289                west_up,
290                east_up,
291            } => OceanMonumentChildPieceKind::DoubleXYRoom {
292                west: Self::persistent_to_ocean_monument_room(west),
293                east: Self::persistent_to_ocean_monument_room(east),
294                west_up: Self::persistent_to_ocean_monument_room(west_up),
295                east_up: Self::persistent_to_ocean_monument_room(east_up),
296            },
297            PersistentOceanMonumentChildPieceKind::DoubleYRoom { room, above } => {
298                OceanMonumentChildPieceKind::DoubleYRoom {
299                    room: Self::persistent_to_ocean_monument_room(room),
300                    above: Self::persistent_to_ocean_monument_room(above),
301                }
302            }
303            PersistentOceanMonumentChildPieceKind::DoubleYZRoom {
304                south,
305                north,
306                south_up,
307                north_up,
308            } => OceanMonumentChildPieceKind::DoubleYZRoom {
309                south: Self::persistent_to_ocean_monument_room(south),
310                north: Self::persistent_to_ocean_monument_room(north),
311                south_up: Self::persistent_to_ocean_monument_room(south_up),
312                north_up: Self::persistent_to_ocean_monument_room(north_up),
313            },
314            PersistentOceanMonumentChildPieceKind::DoubleZRoom { south, north } => {
315                OceanMonumentChildPieceKind::DoubleZRoom {
316                    south: Self::persistent_to_ocean_monument_room(south),
317                    north: Self::persistent_to_ocean_monument_room(north),
318                }
319            }
320            PersistentOceanMonumentChildPieceKind::SimpleRoom { room, main_design } => {
321                OceanMonumentChildPieceKind::SimpleRoom {
322                    room: Self::persistent_to_ocean_monument_room(room),
323                    main_design: *main_design,
324                }
325            }
326            PersistentOceanMonumentChildPieceKind::SimpleTopRoom { room } => {
327                OceanMonumentChildPieceKind::SimpleTopRoom {
328                    room: Self::persistent_to_ocean_monument_room(room),
329                }
330            }
331            PersistentOceanMonumentChildPieceKind::WingRoom { main_design } => {
332                OceanMonumentChildPieceKind::WingRoom {
333                    main_design: *main_design,
334                }
335            }
336            PersistentOceanMonumentChildPieceKind::Penthouse => {
337                OceanMonumentChildPieceKind::Penthouse
338            }
339        }
340    }
341
342    const fn ocean_monument_room_to_persistent(
343        room: OceanMonumentRoomData,
344    ) -> PersistentOceanMonumentRoomData {
345        PersistentOceanMonumentRoomData {
346            index: room.index,
347            has_opening: room.has_opening,
348            has_up_connection: room.has_up_connection,
349        }
350    }
351
352    const fn persistent_to_ocean_monument_room(
353        room: &PersistentOceanMonumentRoomData,
354    ) -> OceanMonumentRoomData {
355        OceanMonumentRoomData {
356            index: room.index,
357            has_opening: room.has_opening,
358            has_up_connection: room.has_up_connection,
359        }
360    }
361
362    const fn fortress_piece_data_to_persistent(
363        data: FortressPieceData,
364    ) -> PersistentNetherFortressPieceData {
365        match data {
366            FortressPieceData::BridgeCrossing => PersistentNetherFortressPieceData::BridgeCrossing,
367            FortressPieceData::BridgeEndFiller { self_seed } => {
368                PersistentNetherFortressPieceData::BridgeEndFiller { self_seed }
369            }
370            FortressPieceData::BridgeStraight => PersistentNetherFortressPieceData::BridgeStraight,
371            FortressPieceData::CastleCorridorStairs => {
372                PersistentNetherFortressPieceData::CastleCorridorStairs
373            }
374            FortressPieceData::CastleCorridorTBalcony => {
375                PersistentNetherFortressPieceData::CastleCorridorTBalcony
376            }
377            FortressPieceData::CastleEntrance => PersistentNetherFortressPieceData::CastleEntrance,
378            FortressPieceData::CastleSmallCorridorCrossing => {
379                PersistentNetherFortressPieceData::CastleSmallCorridorCrossing
380            }
381            FortressPieceData::CastleSmallCorridorLeftTurn { is_needing_chest } => {
382                PersistentNetherFortressPieceData::CastleSmallCorridorLeftTurn { is_needing_chest }
383            }
384            FortressPieceData::CastleSmallCorridor => {
385                PersistentNetherFortressPieceData::CastleSmallCorridor
386            }
387            FortressPieceData::CastleSmallCorridorRightTurn { is_needing_chest } => {
388                PersistentNetherFortressPieceData::CastleSmallCorridorRightTurn { is_needing_chest }
389            }
390            FortressPieceData::CastleStalkRoom => {
391                PersistentNetherFortressPieceData::CastleStalkRoom
392            }
393            FortressPieceData::MonsterThrone { has_placed_spawner } => {
394                PersistentNetherFortressPieceData::MonsterThrone { has_placed_spawner }
395            }
396            FortressPieceData::RoomCrossing => PersistentNetherFortressPieceData::RoomCrossing,
397            FortressPieceData::StairsRoom => PersistentNetherFortressPieceData::StairsRoom,
398        }
399    }
400
401    const fn persistent_to_fortress_piece_data(
402        data: &PersistentNetherFortressPieceData,
403    ) -> FortressPieceData {
404        match data {
405            PersistentNetherFortressPieceData::BridgeCrossing => FortressPieceData::BridgeCrossing,
406            PersistentNetherFortressPieceData::BridgeEndFiller { self_seed } => {
407                FortressPieceData::BridgeEndFiller {
408                    self_seed: *self_seed,
409                }
410            }
411            PersistentNetherFortressPieceData::BridgeStraight => FortressPieceData::BridgeStraight,
412            PersistentNetherFortressPieceData::CastleCorridorStairs => {
413                FortressPieceData::CastleCorridorStairs
414            }
415            PersistentNetherFortressPieceData::CastleCorridorTBalcony => {
416                FortressPieceData::CastleCorridorTBalcony
417            }
418            PersistentNetherFortressPieceData::CastleEntrance => FortressPieceData::CastleEntrance,
419            PersistentNetherFortressPieceData::CastleSmallCorridorCrossing => {
420                FortressPieceData::CastleSmallCorridorCrossing
421            }
422            PersistentNetherFortressPieceData::CastleSmallCorridorLeftTurn { is_needing_chest } => {
423                FortressPieceData::CastleSmallCorridorLeftTurn {
424                    is_needing_chest: *is_needing_chest,
425                }
426            }
427            PersistentNetherFortressPieceData::CastleSmallCorridor => {
428                FortressPieceData::CastleSmallCorridor
429            }
430            PersistentNetherFortressPieceData::CastleSmallCorridorRightTurn {
431                is_needing_chest,
432            } => FortressPieceData::CastleSmallCorridorRightTurn {
433                is_needing_chest: *is_needing_chest,
434            },
435            PersistentNetherFortressPieceData::CastleStalkRoom => {
436                FortressPieceData::CastleStalkRoom
437            }
438            PersistentNetherFortressPieceData::MonsterThrone { has_placed_spawner } => {
439                FortressPieceData::MonsterThrone {
440                    has_placed_spawner: *has_placed_spawner,
441                }
442            }
443            PersistentNetherFortressPieceData::RoomCrossing => FortressPieceData::RoomCrossing,
444            PersistentNetherFortressPieceData::StairsRoom => FortressPieceData::StairsRoom,
445        }
446    }
447
448    const fn stronghold_door_to_persistent(
449        door: StrongholdSmallDoorType,
450    ) -> PersistentStrongholdSmallDoorType {
451        match door {
452            StrongholdSmallDoorType::Opening => PersistentStrongholdSmallDoorType::Opening,
453            StrongholdSmallDoorType::WoodDoor => PersistentStrongholdSmallDoorType::WoodDoor,
454            StrongholdSmallDoorType::Grates => PersistentStrongholdSmallDoorType::Grates,
455            StrongholdSmallDoorType::IronDoor => PersistentStrongholdSmallDoorType::IronDoor,
456        }
457    }
458
459    const fn persistent_to_stronghold_door(
460        door: &PersistentStrongholdSmallDoorType,
461    ) -> StrongholdSmallDoorType {
462        match door {
463            PersistentStrongholdSmallDoorType::Opening => StrongholdSmallDoorType::Opening,
464            PersistentStrongholdSmallDoorType::WoodDoor => StrongholdSmallDoorType::WoodDoor,
465            PersistentStrongholdSmallDoorType::Grates => StrongholdSmallDoorType::Grates,
466            PersistentStrongholdSmallDoorType::IronDoor => StrongholdSmallDoorType::IronDoor,
467        }
468    }
469
470    const fn stronghold_piece_data_to_persistent(
471        data: StrongholdPieceData,
472    ) -> PersistentStrongholdPieceData {
473        match data {
474            StrongholdPieceData::Straight {
475                entry_door,
476                left_child,
477                right_child,
478            } => PersistentStrongholdPieceData::Straight {
479                entry_door: Self::stronghold_door_to_persistent(entry_door),
480                left_child,
481                right_child,
482            },
483            StrongholdPieceData::PrisonHall { entry_door } => {
484                PersistentStrongholdPieceData::PrisonHall {
485                    entry_door: Self::stronghold_door_to_persistent(entry_door),
486                }
487            }
488            StrongholdPieceData::LeftTurn { entry_door } => {
489                PersistentStrongholdPieceData::LeftTurn {
490                    entry_door: Self::stronghold_door_to_persistent(entry_door),
491                }
492            }
493            StrongholdPieceData::RightTurn { entry_door } => {
494                PersistentStrongholdPieceData::RightTurn {
495                    entry_door: Self::stronghold_door_to_persistent(entry_door),
496                }
497            }
498            StrongholdPieceData::RoomCrossing {
499                entry_door,
500                crossing_type,
501            } => PersistentStrongholdPieceData::RoomCrossing {
502                entry_door: Self::stronghold_door_to_persistent(entry_door),
503                crossing_type,
504            },
505            StrongholdPieceData::StraightStairsDown { entry_door } => {
506                PersistentStrongholdPieceData::StraightStairsDown {
507                    entry_door: Self::stronghold_door_to_persistent(entry_door),
508                }
509            }
510            StrongholdPieceData::StairsDown {
511                entry_door,
512                is_source,
513            } => PersistentStrongholdPieceData::StairsDown {
514                entry_door: Self::stronghold_door_to_persistent(entry_door),
515                is_source,
516            },
517            StrongholdPieceData::FiveCrossing {
518                entry_door,
519                left_low,
520                left_high,
521                right_low,
522                right_high,
523            } => PersistentStrongholdPieceData::FiveCrossing {
524                entry_door: Self::stronghold_door_to_persistent(entry_door),
525                left_low,
526                left_high,
527                right_low,
528                right_high,
529            },
530            StrongholdPieceData::ChestCorridor {
531                entry_door,
532                has_placed_chest,
533            } => PersistentStrongholdPieceData::ChestCorridor {
534                entry_door: Self::stronghold_door_to_persistent(entry_door),
535                has_placed_chest,
536            },
537            StrongholdPieceData::Library {
538                entry_door,
539                is_tall,
540            } => PersistentStrongholdPieceData::Library {
541                entry_door: Self::stronghold_door_to_persistent(entry_door),
542                is_tall,
543            },
544            StrongholdPieceData::PortalRoom { has_placed_spawner } => {
545                PersistentStrongholdPieceData::PortalRoom { has_placed_spawner }
546            }
547            StrongholdPieceData::FillerCorridor { steps } => {
548                PersistentStrongholdPieceData::FillerCorridor { steps }
549            }
550        }
551    }
552
553    const fn persistent_to_stronghold_piece_data(
554        data: &PersistentStrongholdPieceData,
555    ) -> StrongholdPieceData {
556        match data {
557            PersistentStrongholdPieceData::Straight {
558                entry_door,
559                left_child,
560                right_child,
561            } => StrongholdPieceData::Straight {
562                entry_door: Self::persistent_to_stronghold_door(entry_door),
563                left_child: *left_child,
564                right_child: *right_child,
565            },
566            PersistentStrongholdPieceData::PrisonHall { entry_door } => {
567                StrongholdPieceData::PrisonHall {
568                    entry_door: Self::persistent_to_stronghold_door(entry_door),
569                }
570            }
571            PersistentStrongholdPieceData::LeftTurn { entry_door } => {
572                StrongholdPieceData::LeftTurn {
573                    entry_door: Self::persistent_to_stronghold_door(entry_door),
574                }
575            }
576            PersistentStrongholdPieceData::RightTurn { entry_door } => {
577                StrongholdPieceData::RightTurn {
578                    entry_door: Self::persistent_to_stronghold_door(entry_door),
579                }
580            }
581            PersistentStrongholdPieceData::RoomCrossing {
582                entry_door,
583                crossing_type,
584            } => StrongholdPieceData::RoomCrossing {
585                entry_door: Self::persistent_to_stronghold_door(entry_door),
586                crossing_type: *crossing_type,
587            },
588            PersistentStrongholdPieceData::StraightStairsDown { entry_door } => {
589                StrongholdPieceData::StraightStairsDown {
590                    entry_door: Self::persistent_to_stronghold_door(entry_door),
591                }
592            }
593            PersistentStrongholdPieceData::StairsDown {
594                entry_door,
595                is_source,
596            } => StrongholdPieceData::StairsDown {
597                entry_door: Self::persistent_to_stronghold_door(entry_door),
598                is_source: *is_source,
599            },
600            PersistentStrongholdPieceData::FiveCrossing {
601                entry_door,
602                left_low,
603                left_high,
604                right_low,
605                right_high,
606            } => StrongholdPieceData::FiveCrossing {
607                entry_door: Self::persistent_to_stronghold_door(entry_door),
608                left_low: *left_low,
609                left_high: *left_high,
610                right_low: *right_low,
611                right_high: *right_high,
612            },
613            PersistentStrongholdPieceData::ChestCorridor {
614                entry_door,
615                has_placed_chest,
616            } => StrongholdPieceData::ChestCorridor {
617                entry_door: Self::persistent_to_stronghold_door(entry_door),
618                has_placed_chest: *has_placed_chest,
619            },
620            PersistentStrongholdPieceData::Library {
621                entry_door,
622                is_tall,
623            } => StrongholdPieceData::Library {
624                entry_door: Self::persistent_to_stronghold_door(entry_door),
625                is_tall: *is_tall,
626            },
627            PersistentStrongholdPieceData::PortalRoom { has_placed_spawner } => {
628                StrongholdPieceData::PortalRoom {
629                    has_placed_spawner: *has_placed_spawner,
630                }
631            }
632            PersistentStrongholdPieceData::FillerCorridor { steps } => {
633                StrongholdPieceData::FillerCorridor { steps: *steps }
634            }
635        }
636    }
637
638    pub(super) fn mineshaft_kind_to_persistent(
639        kind: &MineshaftPieceKind,
640    ) -> PersistentMineshaftPieceKind {
641        match kind {
642            MineshaftPieceKind::Room {
643                child_entrance_boxes,
644            } => PersistentMineshaftPieceKind::Room {
645                child_entrance_boxes: child_entrance_boxes
646                    .iter()
647                    .map(|&b| PersistentBoundingBox::from_bounding_box(b))
648                    .collect(),
649            },
650            MineshaftPieceKind::Corridor {
651                has_rails,
652                spider_corridor,
653                has_placed_spider,
654                num_sections,
655            } => PersistentMineshaftPieceKind::Corridor {
656                has_rails: *has_rails,
657                spider_corridor: *spider_corridor,
658                has_placed_spider: *has_placed_spider,
659                num_sections: *num_sections,
660            },
661            MineshaftPieceKind::Crossing {
662                direction,
663                is_two_floored,
664            } => PersistentMineshaftPieceKind::Crossing {
665                direction: direction_to_2d(Some(*direction)),
666                is_two_floored: *is_two_floored,
667            },
668            MineshaftPieceKind::Stairs => PersistentMineshaftPieceKind::Stairs,
669        }
670    }
671
672    pub(super) fn persistent_to_mineshaft_kind(
673        kind: &PersistentMineshaftPieceKind,
674    ) -> MineshaftPieceKind {
675        match kind {
676            PersistentMineshaftPieceKind::Room {
677                child_entrance_boxes,
678            } => MineshaftPieceKind::Room {
679                child_entrance_boxes: child_entrance_boxes
680                    .iter()
681                    .map(|b| b.to_bounding_box())
682                    .collect(),
683            },
684            PersistentMineshaftPieceKind::Corridor {
685                has_rails,
686                spider_corridor,
687                has_placed_spider,
688                num_sections,
689            } => MineshaftPieceKind::Corridor {
690                has_rails: *has_rails,
691                spider_corridor: *spider_corridor,
692                has_placed_spider: *has_placed_spider,
693                num_sections: *num_sections,
694            },
695            PersistentMineshaftPieceKind::Crossing {
696                direction,
697                is_two_floored,
698            } => MineshaftPieceKind::Crossing {
699                direction: required_direction_from_2d(*direction),
700                is_two_floored: *is_two_floored,
701            },
702            PersistentMineshaftPieceKind::Stairs => MineshaftPieceKind::Stairs,
703        }
704    }
705
706    pub(super) fn structure_piece_payload_to_persistent(
707        payload: &StructurePiecePayload,
708    ) -> PersistentStructurePiecePayload {
709        match payload {
710            StructurePiecePayload::Jigsaw(data) => {
711                PersistentStructurePiecePayload::Jigsaw(Self::jigsaw_piece_data_to_persistent(data))
712            }
713            StructurePiecePayload::Template(data) => {
714                PersistentStructurePiecePayload::Template(PersistentTemplatePieceData {
715                    template_id: data.template_id.clone(),
716                    template_position: [
717                        data.template_position.x,
718                        data.template_position.y,
719                        data.template_position.z,
720                    ],
721                    rotation: rotation_to_persistent(data.rotation),
722                    mirror: mirror_to_persistent(data.mirror),
723                    rotation_pivot: [
724                        data.rotation_pivot.x,
725                        data.rotation_pivot.y,
726                        data.rotation_pivot.z,
727                    ],
728                    block_ignore: block_ignore_to_persistent(data.block_ignore),
729                    late_block_ignore: block_ignore_to_persistent(data.late_block_ignore),
730                    processors: Self::template_processors_to_persistent(&data.processors),
731                    liquid_settings: liquid_settings_to_persistent(data.liquid_settings),
732                    marker_handling: marker_handling_to_persistent(data.marker_handling),
733                    placement_adjustment: placement_adjustment_to_persistent(
734                        data.placement_adjustment,
735                    ),
736                    placement_clip: placement_clip_to_persistent(data.placement_clip),
737                    post_process: post_process_to_persistent(data.post_process),
738                })
739            }
740            StructurePiecePayload::Procedural(data) => PersistentStructurePiecePayload::Procedural(
741                Self::procedural_piece_data_to_persistent(data),
742            ),
743        }
744    }
745
746    pub(super) fn persistent_to_structure_piece_payload(
747        payload: &PersistentStructurePiecePayload,
748    ) -> StructurePiecePayload {
749        match payload {
750            PersistentStructurePiecePayload::Jigsaw(data) => {
751                StructurePiecePayload::Jigsaw(Self::persistent_to_jigsaw_piece_data(data))
752            }
753            PersistentStructurePiecePayload::Template(data) => {
754                StructurePiecePayload::Template(TemplatePieceData {
755                    template_id: data.template_id.clone(),
756                    template_position: IVec3::new(
757                        data.template_position[0],
758                        data.template_position[1],
759                        data.template_position[2],
760                    ),
761                    rotation: rotation_from_persistent(data.rotation),
762                    mirror: mirror_from_persistent(data.mirror),
763                    rotation_pivot: IVec3::new(
764                        data.rotation_pivot[0],
765                        data.rotation_pivot[1],
766                        data.rotation_pivot[2],
767                    ),
768                    block_ignore: block_ignore_from_persistent(data.block_ignore),
769                    late_block_ignore: block_ignore_from_persistent(data.late_block_ignore),
770                    processors: Self::persistent_to_template_processors(&data.processors),
771                    liquid_settings: liquid_settings_from_persistent(data.liquid_settings),
772                    marker_handling: marker_handling_from_persistent(data.marker_handling),
773                    placement_adjustment: placement_adjustment_from_persistent(
774                        &data.placement_adjustment,
775                    ),
776                    placement_clip: placement_clip_from_persistent(data.placement_clip),
777                    post_process: post_process_from_persistent(data.post_process),
778                })
779            }
780            PersistentStructurePiecePayload::Procedural(data) => {
781                StructurePiecePayload::Procedural(Self::persistent_to_procedural_piece_data(data))
782            }
783        }
784    }
785
786    pub(super) fn pool_element_to_persistent(element: &PoolElement) -> PersistentPoolElement {
787        match element {
788            PoolElement::Single {
789                location,
790                processors,
791                projection,
792            } => PersistentPoolElement::Single {
793                location: location.clone(),
794                processors: Self::processors_to_persistent(processors),
795                projection: projection_to_persistent(Some(*projection)),
796            },
797            PoolElement::LegacySingle {
798                location,
799                processors,
800                projection,
801            } => PersistentPoolElement::LegacySingle {
802                location: location.clone(),
803                processors: Self::processors_to_persistent(processors),
804                projection: projection_to_persistent(Some(*projection)),
805            },
806            PoolElement::Empty => PersistentPoolElement::Empty,
807            PoolElement::Feature {
808                feature,
809                projection,
810            } => PersistentPoolElement::Feature {
811                feature: feature.clone(),
812                projection: projection_to_persistent(Some(*projection)),
813            },
814            PoolElement::List {
815                elements,
816                projection,
817            } => PersistentPoolElement::List {
818                elements: elements
819                    .iter()
820                    .map(Self::pool_element_to_persistent)
821                    .collect(),
822                projection: projection_to_persistent(Some(*projection)),
823            },
824        }
825    }
826
827    pub(super) fn persistent_to_pool_element(element: &PersistentPoolElement) -> PoolElement {
828        match element {
829            PersistentPoolElement::Single {
830                location,
831                processors,
832                projection,
833            } => PoolElement::Single {
834                location: location.clone(),
835                processors: Self::persistent_to_processors(processors),
836                projection: required_projection_from_persistent(*projection),
837            },
838            PersistentPoolElement::LegacySingle {
839                location,
840                processors,
841                projection,
842            } => PoolElement::LegacySingle {
843                location: location.clone(),
844                processors: Self::persistent_to_processors(processors),
845                projection: required_projection_from_persistent(*projection),
846            },
847            PersistentPoolElement::Empty => PoolElement::Empty,
848            PersistentPoolElement::Feature {
849                feature,
850                projection,
851            } => PoolElement::Feature {
852                feature: feature.clone(),
853                projection: required_projection_from_persistent(*projection),
854            },
855            PersistentPoolElement::List {
856                elements,
857                projection,
858            } => PoolElement::List {
859                elements: elements
860                    .iter()
861                    .map(Self::persistent_to_pool_element)
862                    .collect(),
863                projection: required_projection_from_persistent(*projection),
864            },
865        }
866    }
867
868    pub(super) fn processors_to_persistent(processors: &ProcessorList) -> PersistentProcessorList {
869        match processors {
870            ProcessorList::Empty => PersistentProcessorList::Empty,
871            ProcessorList::Registry(id) => PersistentProcessorList::Registry(id.clone()),
872        }
873    }
874
875    pub(super) fn persistent_to_processors(processors: &PersistentProcessorList) -> ProcessorList {
876        match processors {
877            PersistentProcessorList::Empty => ProcessorList::Empty,
878            PersistentProcessorList::Registry(id) => ProcessorList::Registry(id.clone()),
879        }
880    }
881
882    pub(super) fn template_processors_to_persistent(
883        processors: &TemplateProcessorList,
884    ) -> PersistentTemplateProcessorList {
885        match processors {
886            TemplateProcessorList::Empty => PersistentTemplateProcessorList::Empty,
887            TemplateProcessorList::Registry(id) => {
888                PersistentTemplateProcessorList::Registry(id.clone())
889            }
890            TemplateProcessorList::OceanRuin {
891                biome_temp,
892                integrity,
893            } => PersistentTemplateProcessorList::OceanRuin {
894                biome_temp: ocean_ruin_biome_temp_to_persistent(*biome_temp),
895                integrity: *integrity,
896            },
897            TemplateProcessorList::RuinedPortal {
898                vertical_placement,
899                properties,
900            } => PersistentTemplateProcessorList::RuinedPortal {
901                vertical_placement: ruined_portal_placement_to_persistent(*vertical_placement),
902                cold: properties.cold,
903                mossiness: properties.mossiness,
904                air_pocket: properties.air_pocket,
905                overgrown: properties.overgrown,
906                vines: properties.vines,
907                replace_with_blackstone: properties.replace_with_blackstone,
908            },
909        }
910    }
911
912    pub(super) fn persistent_to_template_processors(
913        processors: &PersistentTemplateProcessorList,
914    ) -> TemplateProcessorList {
915        match processors {
916            PersistentTemplateProcessorList::Empty => TemplateProcessorList::Empty,
917            PersistentTemplateProcessorList::Registry(id) => {
918                TemplateProcessorList::Registry(id.clone())
919            }
920            PersistentTemplateProcessorList::OceanRuin {
921                biome_temp,
922                integrity,
923            } => TemplateProcessorList::OceanRuin {
924                biome_temp: ocean_ruin_biome_temp_from_persistent(*biome_temp),
925                integrity: *integrity,
926            },
927            PersistentTemplateProcessorList::RuinedPortal {
928                vertical_placement,
929                cold,
930                mossiness,
931                air_pocket,
932                overgrown,
933                vines,
934                replace_with_blackstone,
935            } => TemplateProcessorList::RuinedPortal {
936                vertical_placement: ruined_portal_placement_from_persistent(*vertical_placement),
937                properties: RuinedPortalProperties {
938                    cold: *cold,
939                    mossiness: *mossiness,
940                    air_pocket: *air_pocket,
941                    overgrown: *overgrown,
942                    vines: *vines,
943                    replace_with_blackstone: *replace_with_blackstone,
944                },
945            },
946        }
947    }
948
949    /// Converts structure starts to persistent format for saving.
950    pub(super) fn structure_starts_to_persistent(
951        starts: &StructureStartMap,
952    ) -> Vec<PersistentStructureStart> {
953        let mut persistent: Vec<_> = starts
954            .values()
955            .filter(|start| !start.pieces.is_empty())
956            .map(|start| PersistentStructureStart {
957                structure: start.structure.clone(),
958                chunk_x: start.chunk_pos.0.x,
959                chunk_z: start.chunk_pos.0.y,
960                references: start.references,
961                pieces: start
962                    .pieces
963                    .iter()
964                    .map(|piece| PersistentStructurePiece {
965                        piece_type: piece.piece_type.clone(),
966                        bounding_box: PersistentBoundingBox::from_bounding_box(piece.bounding_box),
967                        gen_depth: piece.gen_depth,
968                        orientation: direction_to_2d(piece.orientation),
969                        payload: Self::structure_piece_payload_to_persistent(&piece.payload),
970                        ground_level_delta: piece.ground_level_delta,
971                        projection: projection_to_persistent(piece.projection),
972                        junctions: piece
973                            .junctions
974                            .iter()
975                            .map(|junction| PersistentJigsawJunction {
976                                source_x: junction.source_pos.x,
977                                source_ground_y: junction.source_pos.y,
978                                source_z: junction.source_pos.z,
979                                delta_y: junction.delta_y,
980                                dest_projection: projection_to_persistent(Some(
981                                    junction.dest_projection,
982                                )),
983                            })
984                            .collect(),
985                    })
986                    .collect(),
987            })
988            .collect();
989
990        persistent.sort_by(|a, b| compare_identifiers(&a.structure, &b.structure));
991        persistent
992    }
993
994    /// Converts structure references to persistent format for saving.
995    pub(super) fn structure_references_to_persistent(
996        refs: &StructureReferenceMap,
997    ) -> Vec<PersistentStructureReference> {
998        let mut persistent: Vec<_> = refs
999            .iter()
1000            .filter(|(_, positions)| !positions.is_empty())
1001            .map(|(structure, positions)| PersistentStructureReference {
1002                structure: structure.clone(),
1003                references: {
1004                    let packed: Vec<_> = positions
1005                        .insertion_order_iter()
1006                        .copied()
1007                        .map(PackedChunkPos::from)
1008                        .collect();
1009                    packed
1010                },
1011            })
1012            .collect();
1013
1014        persistent.sort_by(|a, b| compare_identifiers(&a.structure, &b.structure));
1015        persistent
1016    }
1017
1018    /// Reconstructs structure starts from persistent data.
1019    pub(super) fn persistent_to_structure_starts(
1020        persistent: &[PersistentStructureStart],
1021    ) -> StructureStartMap {
1022        persistent
1023            .iter()
1024            .map(|ps| {
1025                let pieces = ps
1026                    .pieces
1027                    .iter()
1028                    .map(|pp| StructurePiece {
1029                        piece_type: pp.piece_type.clone(),
1030                        bounding_box: pp.bounding_box.to_bounding_box(),
1031                        gen_depth: pp.gen_depth,
1032                        orientation: direction_from_2d(pp.orientation),
1033                        payload: Self::persistent_to_structure_piece_payload(&pp.payload),
1034                        ground_level_delta: pp.ground_level_delta,
1035                        junctions: pp
1036                            .junctions
1037                            .iter()
1038                            .map(|junction| JigsawJunction {
1039                                source_pos: IVec3::new(
1040                                    junction.source_x,
1041                                    junction.source_ground_y,
1042                                    junction.source_z,
1043                                ),
1044                                delta_y: junction.delta_y,
1045                                dest_projection: required_projection_from_persistent(
1046                                    junction.dest_projection,
1047                                ),
1048                            })
1049                            .collect(),
1050                        projection: projection_from_persistent(pp.projection),
1051                    })
1052                    .collect();
1053
1054                let terrain_adjustment = REGISTRY
1055                    .structures
1056                    .by_key(&ps.structure)
1057                    .map_or(TerrainAdjustment::None, |structure| {
1058                        structure.terrain_adjustment
1059                    });
1060                let mut start = StructureStart::new(
1061                    ps.structure.clone(),
1062                    ChunkPos::new(ps.chunk_x, ps.chunk_z),
1063                    pieces,
1064                    terrain_adjustment,
1065                );
1066                start.references = ps.references;
1067                (ps.structure.clone(), start)
1068            })
1069            .collect()
1070    }
1071
1072    /// Reconstructs structure references from persistent data.
1073    pub(super) fn persistent_to_structure_references(
1074        persistent: &[PersistentStructureReference],
1075    ) -> StructureReferenceMap {
1076        persistent
1077            .iter()
1078            .map(|pr| {
1079                let positions = pr
1080                    .references
1081                    .iter()
1082                    .map(|&packed| packed.to_chunk_pos())
1083                    .collect();
1084                (pr.structure.clone(), positions)
1085            })
1086            .collect()
1087    }
1088}