1use super::{
2 BoundingBox, Direction, IVec3, Identifier, LiquidSettingsData, Rotation, StructureBlockIgnore,
3 StructureMirror, StructurePiece, StructurePiecePayload, TemplateMarkerHandling,
4 TemplatePieceData, TemplatePlacementAdjustment, TemplatePlacementClip, TemplatePostProcess,
5 TemplateProcessorList,
6};
7
8pub(super) fn template_size(name: &str) -> [i32; 3] {
9 match name {
10 "entrance" => [21, 19, 16],
11 "wall_flat" | "wall_window" => [2, 8, 8],
12 "wall_corner" => [9, 8, 2],
13 "corridor_floor" => [7, 8, 7],
14 "carpet_north" => [5, 1, 2],
15 "carpet_east" => [2, 1, 5],
16 "carpet_south_1" => [8, 8, 3],
17 "carpet_south_2" => [8, 11, 3],
18 "carpet_west_1" => [3, 8, 8],
19 "carpet_west_2" => [3, 11, 8],
20 "indoors_wall_1" | "indoors_door_1" => [1, 8, 8],
21 "indoors_wall_2" | "indoors_door_2" => [1, 11, 8],
22 "roof" => [8, 1, 8],
23 "roof_corner" | "roof_inner_corner" => [4, 4, 4],
24 "roof_front" => [4, 4, 8],
25 "small_wall" => [2, 4, 8],
26 "small_wall_corner" => [2, 4, 2],
27 s if s.starts_with("1x1_a") => [7, 8, 7],
28 s if s.starts_with("1x1_b") => [7, 11, 7],
29 "1x2_c_stairs" | "1x2_d_stairs" => [7, 22, 15],
30 s if s.starts_with("1x2_c") || s.starts_with("1x2_d") || s.starts_with("1x2_se") => {
31 [7, 11, 15]
32 }
33 s if s.starts_with("1x2_a") || s.starts_with("1x2_b") || s.starts_with("1x2_s") => {
34 [7, 8, 15]
35 }
36 s if s.starts_with("2x2_a") => [15, 8, 15],
37 s if s.starts_with("2x2_b") || s.starts_with("2x2_s") => [15, 11, 15],
38 _ => {
39 tracing::warn!("Unknown mansion template: {name}, using 1x1x1");
40 [1, 1, 1]
41 }
42 }
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub(super) enum Mirror {
47 None,
48 LeftRight,
49 FrontBack,
50}
51
52pub(super) fn piece_bb(pos: IVec3, size: IVec3, rotation: Rotation, mirror: Mirror) -> BoundingBox {
53 let dx = size.x - 1;
54 let dy = size.y - 1;
55 let dz = size.z - 1;
56 let (x1, z1) = apply_mirror(0, 0, mirror);
57 let (x2, z2) = apply_mirror(dx, dz, mirror);
58 let c1 = rotation.transform_pos(IVec3::new(x1, 0, z1), IVec3::ZERO);
59 let c2 = rotation.transform_pos(IVec3::new(x2, dy, z2), IVec3::ZERO);
60 BoundingBox::new(
61 IVec3::new(c1.x.min(c2.x), c1.y.min(c2.y), c1.z.min(c2.z)) + pos,
62 IVec3::new(c1.x.max(c2.x), c1.y.max(c2.y), c1.z.max(c2.z)) + pos,
63 )
64}
65
66pub(super) const fn apply_mirror(x: i32, z: i32, mirror: Mirror) -> (i32, i32) {
67 match mirror {
68 Mirror::None => (x, z),
69 Mirror::FrontBack => (-x, z),
70 Mirror::LeftRight => (x, -z),
71 }
72}
73
74pub(super) const fn structure_mirror(mirror: Mirror) -> StructureMirror {
75 match mirror {
76 Mirror::None => StructureMirror::None,
77 Mirror::FrontBack => StructureMirror::FrontBack,
78 Mirror::LeftRight => StructureMirror::LeftRight,
79 }
80}
81
82#[derive(Debug, PartialEq, Eq)]
83pub(super) struct MansionTemplatePiece {
84 template_name: String,
85 position: IVec3,
86 rotation: Rotation,
87 mirror: Mirror,
88}
89
90impl MansionTemplatePiece {
91 pub(super) fn new(
92 template_name: impl Into<String>,
93 position: IVec3,
94 rotation: Rotation,
95 mirror: Mirror,
96 ) -> Self {
97 Self {
98 template_name: template_name.into(),
99 position,
100 rotation,
101 mirror,
102 }
103 }
104
105 pub(super) fn bounding_box(&self) -> BoundingBox {
106 piece_bb(
107 self.position,
108 IVec3::from(template_size(&self.template_name)),
109 self.rotation,
110 self.mirror,
111 )
112 }
113
114 pub(super) fn template_id(&self) -> Identifier {
115 Identifier::vanilla(format!("woodland_mansion/{}", self.template_name))
116 }
117
118 pub(super) fn into_structure_piece(self) -> StructurePiece {
119 let bounding_box = self.bounding_box();
120 let mirror = structure_mirror(self.mirror);
121 let template_id = self.template_id();
122 StructurePiece {
123 piece_type: Identifier::new_static("minecraft", "wmp"),
124 bounding_box,
125 gen_depth: 0,
126 orientation: Some(Direction::North),
127 payload: StructurePiecePayload::Template(TemplatePieceData {
128 template_id,
129 template_position: self.position,
130 rotation: self.rotation,
131 mirror,
132 rotation_pivot: IVec3::ZERO,
133 block_ignore: StructureBlockIgnore::StructureBlock,
134 late_block_ignore: StructureBlockIgnore::None,
135 processors: TemplateProcessorList::Empty,
136 liquid_settings: LiquidSettingsData::ApplyWaterlogging,
137 marker_handling: TemplateMarkerHandling::WoodlandMansion,
138 placement_adjustment: TemplatePlacementAdjustment::None,
139 placement_clip: TemplatePlacementClip::CenterChunk,
140 post_process: TemplatePostProcess::None,
141 }),
142 ground_level_delta: 0,
143 junctions: Vec::new(),
144 projection: None,
145 }
146 }
147}
148
149pub(super) fn add_piece(
150 pieces: &mut Vec<MansionTemplatePiece>,
151 template_name: impl Into<String>,
152 position: IVec3,
153 rotation: Rotation,
154 mirror: Mirror,
155) {
156 pieces.push(MansionTemplatePiece::new(
157 template_name,
158 position,
159 rotation,
160 mirror,
161 ));
162}
163
164pub(super) fn relative(pos: IVec3, rotation: Rotation, dir: Direction, amount: i32) -> IVec3 {
165 let rotated = rotation.rotate(dir);
166 let offset = rotated.offset_vec();
167 pos + offset * amount
168}
169
170pub(super) const fn above(pos: IVec3, amount: i32) -> IVec3 {
171 IVec3::new(pos.x, pos.y + amount, pos.z)
172}
173
174pub(super) const fn zero_pos_transform(
175 zero: IVec3,
176 rotation: Rotation,
177 size_x: i32,
178 size_z: i32,
179) -> IVec3 {
180 let sx = size_x - 1;
181 let sz = size_z - 1;
182 let (dx, dz) = match rotation {
183 Rotation::None => (0, 0),
184 Rotation::Clockwise90 => (sz, 0),
185 Rotation::Clockwise180 => (sx, sz),
186 Rotation::CounterClockwise90 => (0, sx),
187 };
188 IVec3::new(zero.x + dx, zero.y, zero.z + dz)
189}
190
191pub(super) const fn compose_rotation(base: Rotation, add: Rotation) -> Rotation {
192 base.then(add)
193}
194
195pub(super) const fn dir_from_2d(value: i32) -> Direction {
196 match value & 3 {
197 0 => Direction::South,
198 1 => Direction::West,
199 2 => Direction::North,
200 _ => Direction::East,
201 }
202}