vintage_schematics/formats/
internal.rs1use serde::{Deserialize, Serialize};
5
6use crate::{
7 Map,
8 convert::{
9 block::{VS_FLOWER_POT_CODE, convert_block},
10 entities::Sign,
11 },
12 entity::{ItemClass, ItemStack, Value},
13 formats::{
14 Settings,
15 common::{MinecraftBlockEntity, Xyz},
16 },
17};
18
19pub type PropertyMap = Map<String, String>;
21
22pub type EntityMap = Map<String, Value>;
24
25#[derive(Debug, Clone, Serialize)]
29pub struct Internal {
30 pub block_codes: BlockCodes,
32
33 pub blocks: Vec<Block>,
35
36 pub tile_entities: Vec<MinecraftBlockEntity>,
38
39 pub size: Xyz,
41}
42
43#[derive(Debug, Clone, Serialize)]
45pub enum BlockCodes {
46 VintageStory {
47 codes: Vec<VintageStoryBlockCode>,
48 properties: Vec<EntityMap>,
49 },
50 Minecraft(Vec<MinecraftBlockCode>),
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
54#[serde(rename_all = "PascalCase")]
55pub struct MinecraftBlockCode {
56 pub name: String,
57 #[serde(default)]
58 pub properties: PropertyMap,
59}
60
61#[derive(Debug, Clone, Serialize)]
62pub struct VintageStoryBlockCode {
63 pub name: String,
67
68 pub properties: Option<usize>,
70}
71
72#[derive(Debug, Clone, Serialize)]
73pub struct Block {
74 pub id: usize,
75 pub position: Xyz,
76}
77
78impl Internal {
79 pub fn convert_to_vintage_story(&mut self, settings: &Settings) {
81 let (new_blocks, mut new_properties) = if let BlockCodes::Minecraft(block_codes) = &self.block_codes {
82 let mut new_blocks = Vec::with_capacity(block_codes.len());
83 let mut new_properties = Vec::new();
84 let mut extra_blocks = Vec::new();
85
86 for block in block_codes {
87 let (code, properties) = match convert_block(block, settings) {
92 Some(result) => result,
93 None if settings.replace_missing => (String::from("game:leaves-placed-birch"), None),
94 None => (String::from("game:air"), None), };
96
97 #[allow(clippy::option_if_let_else)]
98 let properties = if let Some(mut properties) = properties {
99 let existing = new_properties.iter().position(|p| *p == properties);
101
102 Some(
103 if let Some(existing) = existing
104 && !properties.contains_key("unique!")
105 {
106 existing
108 } else {
109 if code == VS_FLOWER_POT_CODE
110 && let Some(Value::String(flower)) = properties.remove("flower")
111 {
112 let flower_id =
118 if let Some(id) = new_blocks.iter().position(|b: &VintageStoryBlockCode| b.name == flower) {
119 id
120 } else if let Some(id) = extra_blocks.iter().position(|e| e == &flower) {
121 block_codes.len() + id
126 } else {
127 extra_blocks.push(flower);
130 block_codes.len() + extra_blocks.len() - 1
131 };
132
133 let item_stack = ItemStack {
135 class: ItemClass::Block,
136 id: i32::try_from(flower_id).unwrap_or_default(),
137 stack_size: 1,
138 stack_attributes: Map::new(),
139 };
140
141 properties.insert(String::from("meshAngle"), Value::Float(0.0));
142 properties.insert(
143 String::from("inventory"),
144 Value::Tree(Map::from([
145 (String::from("qslots"), Value::Integer(1)),
146 (
147 String::from("slots"),
148 Value::Tree(Map::from([(String::from("0"), Value::ItemStack(Some(item_stack)))])),
149 ),
150 ])),
151 );
152 }
153 new_properties.push(properties);
155 new_properties.len() - 1
156 },
157 )
158 } else {
159 None
160 };
161
162 let block = VintageStoryBlockCode { name: code, properties };
163 new_blocks.push(block);
164 }
165
166 new_blocks.extend(extra_blocks.into_iter().map(|name| VintageStoryBlockCode { name, properties: None }));
167 (new_blocks, new_properties)
168 } else {
169 return;
171 };
172
173 for tile_entity in &self.tile_entities {
175 if let Ok(sign) = Sign::try_from(tile_entity)
177 && let Some(block) = self.blocks.iter().find(|block| block.position == tile_entity.position())
178 && let Some(block) = new_blocks.get(block.id)
179 && let Some(properties) = block.properties
180 && let Some(properties) = new_properties.get_mut(properties)
181 {
182 let (r, g, b) = sign.colour();
183 let colour = i32::from_be_bytes([0xFF, r, g, b]);
186
187 properties.extend([
188 (String::from("color"), Value::Integer(colour)),
189 (String::from("fontSize"), Value::Float(16.0)),
190 (String::from("text"), Value::String(sign.text())),
191 ]);
192 properties.remove("unique!");
193 }
194 }
195
196 self.block_codes = BlockCodes::VintageStory {
197 codes: new_blocks,
198 properties: new_properties,
199 };
200 }
201}