concinnity_core/components/
room.rs1use concinnity_asset::cook;
7
8use crate::ecs::asset_id::AssetId;
9use crate::ecs::{Component, PayloadLocator, TextureHandle};
10
11#[derive(Debug, serde::Serialize, serde::Deserialize)]
24pub struct Room {
25 pub asset_id: AssetId,
27 pub half_width: f32,
29 pub half_depth: f32,
31 pub ceiling_height: f32,
33 pub texture: Option<TextureHandle>,
35 pub wall_texture: Option<TextureHandle>,
37 pub floor_texture: Option<TextureHandle>,
39 pub ceiling_texture: Option<TextureHandle>,
41 pub locator: Option<PayloadLocator>,
43}
44
45impl Room {
46 pub fn effective_texture(&self) -> Option<TextureHandle> {
48 [
49 self.texture,
50 self.wall_texture,
51 self.floor_texture,
52 self.ceiling_texture,
53 ]
54 .into_iter()
55 .flatten()
56 .next()
57 }
58}
59
60impl Room {
61 pub fn bake(args: cook::Room) -> Self {
65 let (half_width, half_depth, ceiling_height) = if let Some([w, d, h]) = args.size {
66 (w / 2.0, d / 2.0, h)
67 } else {
68 (args.half_width, args.half_depth, args.ceiling_height)
69 };
70 Self {
71 asset_id: AssetId::default(),
72 half_width,
73 half_depth,
74 ceiling_height,
75 texture: args.texture,
76 wall_texture: args.wall_texture,
77 floor_texture: args.floor_texture,
78 ceiling_texture: args.ceiling_texture,
79 locator: None,
80 }
81 }
82}
83
84impl Component for Room {
85 const NAME: &'static str = "Room";
86
87 fn from_baked(bytes: &[u8]) -> Result<Self, crate::result::CnResult> {
88 Ok(crate::blob::decode_exact(bytes)?)
89 }
90
91 fn inject_locator(&mut self, locator: PayloadLocator) {
92 self.locator = Some(locator);
93 }
94
95 fn inject_name(&mut self, id: AssetId) {
96 self.asset_id = id;
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn effective_texture_returns_texture_field_first() {
106 let room = Room {
107 asset_id: AssetId::default(),
108 half_width: 8.0,
109 half_depth: 10.0,
110 ceiling_height: 3.5,
111 texture: Some(TextureHandle(1)),
112 wall_texture: Some(TextureHandle(2)),
113 floor_texture: None,
114 ceiling_texture: None,
115 locator: None,
116 };
117 assert_eq!(room.effective_texture(), Some(TextureHandle(1)));
118 }
119
120 #[test]
121 fn effective_texture_falls_back_to_wall_texture() {
122 let room = Room {
123 asset_id: AssetId::default(),
124 half_width: 8.0,
125 half_depth: 10.0,
126 ceiling_height: 3.5,
127 texture: None,
128 wall_texture: Some(TextureHandle(7)),
129 floor_texture: None,
130 ceiling_texture: None,
131 locator: None,
132 };
133 assert_eq!(room.effective_texture(), Some(TextureHandle(7)));
134 }
135
136 #[test]
137 fn effective_texture_returns_none_when_all_unset() {
138 let room = Room::bake(cook::Room::default());
139 assert_eq!(room.effective_texture(), None);
140 }
141
142 #[test]
143 fn from_args_resolves_size_shorthand() {
144 let args = cook::Room {
145 size: Some([16.0, 20.0, 3.5]),
146 ..cook::Room::default()
147 };
148 let room = Room::bake(args);
149 assert_eq!(room.half_width, 8.0);
150 assert_eq!(room.half_depth, 10.0);
151 assert_eq!(room.ceiling_height, 3.5);
152 }
153
154 #[test]
155 fn from_args_uses_explicit_half_extents_when_no_size() {
156 let args = cook::Room {
157 half_width: 5.0,
158 half_depth: 7.0,
159 ceiling_height: 4.0,
160 size: None,
161 ..cook::Room::default()
162 };
163 let room = Room::bake(args);
164 assert_eq!(room.half_width, 5.0);
165 assert_eq!(room.half_depth, 7.0);
166 assert_eq!(room.ceiling_height, 4.0);
167 }
168}