Skip to main content

steel_worldgen/structure/mansion/
template.rs

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}