1use theframework::prelude::*;
2
3use crate::prelude::*;
4
5#[derive(Serialize, Deserialize, Clone, Debug)]
6pub struct Item {
7 pub id: u32,
9
10 pub position: Vec3<f32>,
12
13 pub creator_id: Uuid,
15
16 pub item_type: String,
18
19 pub max_capacity: u32,
21
22 pub container: Option<Vec<Item>>,
24
25 pub attributes: ValueContainer,
27
28 pub dirty_flags: u8,
30
31 pub dirty_attributes: FxHashSet<String>,
33}
34
35impl Default for Item {
36 fn default() -> Self {
37 Self::new()
38 }
39}
40
41impl Item {
42 pub fn new() -> Self {
43 Self {
44 id: 0,
45 position: Vec3::new(0.0, 1.0, 0.0),
46 creator_id: Uuid::new_v4(),
47 item_type: String::new(),
48 max_capacity: 1, container: None,
50 attributes: ValueContainer::default(),
51 dirty_flags: 0,
52 dirty_attributes: FxHashSet::default(),
53 }
54 }
55
56 pub fn get_pos_xz(&self) -> Vec2<f32> {
58 Vec2::new(self.position.x, self.position.z)
59 }
60
61 pub fn set_position(&mut self, new_position: Vec3<f32>) {
63 if self.position != new_position {
64 self.position = new_position;
65 self.mark_dirty_field(0b0100);
66 }
67 }
68
69 pub fn set_max_capacity(&mut self, new_max_capacity: u32) {
71 if self.max_capacity != new_max_capacity {
72 self.max_capacity = new_max_capacity;
73 self.mark_dirty_field(0b0010);
74 }
75 }
76
77 pub fn is_container(&self) -> bool {
79 self.container.is_some()
80 }
81
82 pub fn has_space(&self) -> bool {
84 if let Some(container) = &self.container {
85 container.len() < self.max_capacity as usize
86 } else {
87 false
88 }
89 }
90
91 pub fn add_to_container(&mut self, item: Item) -> Result<(), String> {
93 if let Some(container) = self.container.as_mut() {
94 if container.len() < self.max_capacity as usize {
95 container.push(item);
96 self.mark_dirty_field(0b0001);
97 Ok(())
98 } else {
99 Err("Container is full.".to_string())
100 }
101 } else {
102 Err("This item is not a container.".to_string())
103 }
104 }
105
106 pub fn remove_from_container(&mut self, item_id: u32) -> Result<Item, String> {
108 self.mark_dirty_field(0b0001);
109 if let Some(container) = self.container.as_mut() {
110 if let Some(index) = container.iter().position(|item| item.id == item_id) {
111 return Ok(container.remove(index));
112 }
113 Err("Item not found in container.".to_string())
114 } else {
115 Err("This item is not a container.".to_string())
116 }
117 }
118
119 pub fn set_attribute(&mut self, key: &str, value: Value) {
121 self.attributes.set(key, value);
122 self.mark_dirty_attribute(key);
123 }
124
125 pub fn get_attribute(&self, key: &str) -> Option<&Value> {
127 self.attributes.get(key)
128 }
129
130 pub fn get_attr_string(&self, key: &str) -> Option<String> {
132 self.attributes.get(key).map(|value| value.to_string())
133 }
134
135 pub fn get_attr_uuid(&self, key: &str) -> Option<Uuid> {
137 if let Some(Value::Id(value)) = self.attributes.get(key) {
138 Some(*value)
139 } else {
140 None
141 }
142 }
143
144 fn mark_dirty_field(&mut self, field: u8) {
146 self.dirty_flags |= field;
147 }
148
149 pub fn mark_dirty_attribute(&mut self, key: &str) {
151 self.dirty_attributes.insert(key.to_string());
152 }
153
154 pub fn mark_all_dirty(&mut self) {
156 self.dirty_flags = 0b0111; for key in self.attributes.keys() {
158 self.dirty_attributes.insert(key.clone());
159 }
160 if let Some(container) = &mut self.container {
162 for item in container.iter_mut() {
163 item.mark_all_dirty();
164 }
165 }
166 }
167
168 pub fn clear_dirty(&mut self) {
170 self.dirty_flags = 0;
171 self.dirty_attributes.clear();
172 if let Some(container) = &mut self.container {
174 for item in container.iter_mut() {
175 item.clear_dirty();
176 }
177 }
178 }
179
180 pub fn is_dirty(&self) -> bool {
182 self.dirty_flags != 0
183 || !self.dirty_attributes.is_empty()
184 || self
185 .container
186 .as_ref()
187 .map(|c| c.iter().any(|item| item.is_dirty()))
188 .unwrap_or(false)
189 }
190
191 pub fn get_update(&self) -> ItemUpdate {
193 let mut updated_attributes = FxHashMap::default();
194 for key in &self.dirty_attributes {
195 if let Some(value) = self.attributes.get(key) {
196 updated_attributes.insert(key.clone(), value.clone());
197 }
198 }
199
200 let container_updates = self.container.as_ref().map(|container| {
201 container
202 .iter()
203 .filter(|item| item.is_dirty())
204 .flat_map(|item| [item.get_update()])
205 .collect()
206 });
207
208 ItemUpdate {
209 id: self.id,
210 creator_id: self.creator_id,
211 item_type: if self.dirty_flags & 0b0001 != 0 {
212 Some(self.item_type.clone())
213 } else {
214 None
215 },
216 max_capacity: if self.dirty_flags & 0b0010 != 0 {
217 Some(self.max_capacity)
218 } else {
219 None
220 },
221 position: if self.dirty_flags & 0b0100 != 0 {
222 Some(self.position)
223 } else {
224 None
225 },
226 attributes: updated_attributes,
227 container_updates,
228 }
229 }
230
231 pub fn apply_update(&mut self, update: ItemUpdate) {
233 if self.id != update.id {
235 eprintln!("Update ID does not match Item ID!");
236 return;
237 }
238
239 self.creator_id = update.creator_id;
240
241 if let Some(new_item_type) = update.item_type {
243 self.item_type = new_item_type;
244 }
245 if let Some(new_max_capacity) = update.max_capacity {
246 self.max_capacity = new_max_capacity;
247 }
248 if let Some(new_position) = update.position {
249 self.position = new_position;
250 }
251
252 for (key, value) in update.attributes {
254 self.attributes.set(&key, value.clone());
255 }
256
257 if let Some(container_updates) = update.container_updates {
259 if let Some(container) = &mut self.container {
260 for update in container_updates {
261 if let Some(item) = container.iter_mut().find(|item| item.id == update.id) {
262 item.apply_update(update);
263 }
264 }
265 }
266 }
267 }
268}
269
270#[derive(Debug, Clone, Serialize, Deserialize)]
272pub struct ItemUpdate {
273 pub id: u32,
274 pub creator_id: Uuid,
275 pub item_type: Option<String>,
276 pub max_capacity: Option<u32>,
277 pub position: Option<Vec3<f32>>,
278 pub attributes: FxHashMap<String, Value>,
279 pub container_updates: Option<Vec<ItemUpdate>>,
280}
281
282impl ItemUpdate {
283 pub fn pack(&self) -> Vec<u8> {
285 bincode::serialize(self).unwrap_or_else(|_| Vec::new())
286 }
287
288 pub fn unpack(data: &[u8]) -> Self {
290 bincode::deserialize(data).unwrap_or_else(|_| Self {
291 id: 0,
292 creator_id: Uuid::nil(),
293 item_type: None,
294 max_capacity: None,
295 position: None,
296 attributes: FxHashMap::default(),
297 container_updates: None,
298 })
299 }
300}