vintage_schematics/formats/
vanilla.rs1use std::io::Read;
4
5use color_eyre::{eyre, eyre::Context};
6use serde::{Deserialize, Serialize};
7
8use crate::formats::{
9 Loadable, ToInternal,
10 common::{FLATTENING_VERSION, MODERNISED_BLOCKS, MinecraftBlockData, MinecraftBlockEntity},
11 internal::{Block, BlockCodes, Internal, MinecraftBlockCode},
12 read, should_reject,
13};
14
15#[derive(Debug, Clone, Deserialize, Serialize)]
17pub struct Vanilla {
18 pub size: (i32, i32, i32),
19 pub blocks: Vec<VanillaBlock>,
20 pub palette: Vec<MinecraftBlockCode>,
21
22 #[serde(rename = "DataVersion")]
23 pub data_version: i32,
24}
25
26#[derive(Debug, Clone, Deserialize, Serialize)]
27pub struct VanillaBlock {
28 pub state: u32,
29 pub pos: (i32, i32, i32),
30 #[serde(default)]
31 nbt: Option<MinecraftBlockData>,
32}
33
34impl Loadable for Vanilla {
35 fn load(reader: impl Read, compressed: bool) -> eyre::Result<Self> {
36 let mut schematic: Self = read(reader, compressed).context("failed to load schematic")?;
37 schematic.modernise();
38 Ok(schematic)
39 }
40
41 fn modernise(&mut self) {
42 if self.data_version < FLATTENING_VERSION {
43 for (old, new) in MODERNISED_BLOCKS {
44 if let Some(position) = self.palette.iter().position(|c| c.name == *old) {
45 self.palette[position].name = new.to_string();
46 }
47 }
48 }
49 }
50}
51
52impl ToInternal for Vanilla {
53 fn to_internal(self) -> eyre::Result<Internal> {
54 let (rejected, block_codes): (Vec<bool>, BlockCodes) = {
57 let mut rejected = Vec::with_capacity(self.palette.len());
58 let mut block_codes = Vec::with_capacity(self.palette.len());
59
60 for block in self.palette {
61 let is_rejected = should_reject(&block);
62 rejected.push(is_rejected);
63 if !is_rejected {
64 block_codes.push(block);
65 }
66 }
67
68 (rejected, BlockCodes::Minecraft(block_codes))
69 };
70
71 let mut current_id = 0;
72 let mut ids = Vec::with_capacity(rejected.len());
73 for &is_rejected in &rejected {
74 ids.push(current_id);
75 if !is_rejected {
76 current_id += 1;
77 }
78 }
79
80 let tile_entities = {
81 let mut tile_entities = Vec::new();
82 for block in &self.blocks {
83 if let Some(nbt) = &block.nbt {
84 tile_entities.push(MinecraftBlockEntity {
85 id: nbt.id.clone(),
86 x: block.pos.0,
87 y: block.pos.1,
88 z: block.pos.2,
89 components: nbt.components.clone(),
90 });
91 }
92 }
93
94 tile_entities
95 };
96
97 let blocks = self
98 .blocks
99 .into_iter()
100 .map(|b| (b.state as usize, b))
101 .filter(|(id, _)| !rejected[*id])
102 .map(|(id, b)| {
103 Block {
104 id: ids[id],
107 position: b.pos.into(),
108 }
109 })
110 .collect();
111
112 Ok(Internal {
113 block_codes,
114 blocks,
115 tile_entities,
116 size: self.size.into(),
117 })
118 }
119}