1use crate::prelude::*;
2use indexmap::IndexMap;
3pub use rusterix::map::*;
4use theframework::prelude::*;
5
6fn default_target_fps() -> u32 {
8 30
9}
10
11fn default_tick_ms() -> u32 {
13 250
14}
15
16#[derive(Serialize, Deserialize, Clone, Debug)]
17pub struct Project {
18 pub name: String,
19 pub regions: Vec<Region>,
20 pub tilemaps: Vec<Tilemap>,
21
22 #[serde(default)]
24 pub tiles: IndexMap<Uuid, rusterix::Tile>,
25
26 #[serde(default)]
27 pub time: TheTime,
28
29 #[serde(default)]
30 pub characters: IndexMap<Uuid, Character>,
31 #[serde(default)]
32 pub items: IndexMap<Uuid, Item>,
33
34 #[serde(default)]
35 pub screens: IndexMap<Uuid, Screen>,
36
37 #[serde(default)]
38 pub assets: IndexMap<Uuid, Asset>,
39
40 #[serde(default)]
41 pub palette: ThePalette,
42
43 #[serde(default = "default_target_fps")]
44 pub target_fps: u32,
45
46 #[serde(default = "default_tick_ms")]
47 pub tick_ms: u32,
48
49 #[serde(default)]
50 pub config: String,
51
52 #[serde(default)]
53 pub avatars: IndexMap<Uuid, Avatar>,
54}
55
56impl Default for Project {
57 fn default() -> Self {
58 Self::new()
59 }
60}
61
62impl Project {
63 pub fn new() -> Self {
64 let region = Region::default();
65
66 Self {
67 name: String::new(),
68
69 regions: vec![region],
70 tilemaps: vec![],
71
72 tiles: IndexMap::default(),
73
74 time: TheTime::default(),
75
76 characters: IndexMap::default(),
77 items: IndexMap::default(),
78
79 screens: IndexMap::default(),
80 assets: IndexMap::default(),
81
82 palette: ThePalette::default(),
83
84 target_fps: default_target_fps(),
85 tick_ms: default_tick_ms(),
86
87 avatars: IndexMap::default(),
88
89 config: String::new(),
90 }
91 }
92
93 pub fn add_character(&mut self, character: Character) {
95 self.characters.insert(character.id, character);
96 }
97
98 pub fn remove_character(&mut self, id: &Uuid) {
100 self.characters.shift_remove(id);
101 }
102
103 pub fn sorted_character_list(&self) -> Vec<(Uuid, String)> {
105 let mut entries: Vec<(Uuid, String)> = self
106 .characters
107 .iter()
108 .map(|(uuid, data)| (*uuid, data.name.clone()))
109 .collect();
110
111 entries.sort_by(|a, b| a.1.cmp(&b.1));
112 entries
113 }
114
115 pub fn sorted_item_list(&self) -> Vec<(Uuid, String)> {
117 let mut entries: Vec<(Uuid, String)> = self
118 .items
119 .iter()
120 .map(|(uuid, data)| (*uuid, data.name.clone()))
121 .collect();
122
123 entries.sort_by(|a, b| a.1.cmp(&b.1));
124 entries
125 }
126
127 pub fn add_avatar(&mut self, avatar: Avatar) {
129 self.avatars.insert(avatar.id, avatar);
130 }
131
132 pub fn remove_avatar(&mut self, id: &Uuid) {
134 self.avatars.shift_remove(id);
135 }
136
137 pub fn find_avatar_for_animation(&self, animation_id: &Uuid) -> Option<&Avatar> {
139 self.avatars
140 .values()
141 .find(|a| a.animations.iter().any(|anim| anim.id == *animation_id))
142 }
143
144 pub fn get_editing_texture(
146 &self,
147 editing_ctx: &PixelEditingContext,
148 ) -> Option<&rusterix::Texture> {
149 match editing_ctx {
150 PixelEditingContext::None => None,
151 PixelEditingContext::Tile(tile_id, frame_index) => {
152 let tile = self.tiles.get(tile_id)?;
153 tile.textures.get(*frame_index)
154 }
155 PixelEditingContext::AvatarFrame(
156 avatar_id,
157 anim_id,
158 perspective_index,
159 frame_index,
160 ) => {
161 let avatar = self.avatars.get(avatar_id)?;
162 let anim = avatar.animations.iter().find(|a| a.id == *anim_id)?;
163 let perspective = anim.perspectives.get(*perspective_index)?;
164 perspective.frames.get(*frame_index).map(|f| &f.texture)
165 }
166 }
167 }
168
169 pub fn get_editing_texture_mut(
171 &mut self,
172 editing_ctx: &PixelEditingContext,
173 ) -> Option<&mut rusterix::Texture> {
174 match editing_ctx {
175 PixelEditingContext::None => None,
176 PixelEditingContext::Tile(tile_id, frame_index) => {
177 let tile = self.tiles.get_mut(tile_id)?;
178 tile.textures.get_mut(*frame_index)
179 }
180 PixelEditingContext::AvatarFrame(
181 avatar_id,
182 anim_id,
183 perspective_index,
184 frame_index,
185 ) => {
186 let avatar = self.avatars.get_mut(avatar_id)?;
187 let anim = avatar.animations.iter_mut().find(|a| a.id == *anim_id)?;
188 let perspective = anim.perspectives.get_mut(*perspective_index)?;
189 perspective
190 .frames
191 .get_mut(*frame_index)
192 .map(|f| &mut f.texture)
193 }
194 }
195 }
196
197 pub fn get_editing_avatar_frame(
199 &self,
200 editing_ctx: &PixelEditingContext,
201 ) -> Option<&rusterix::AvatarAnimationFrame> {
202 match editing_ctx {
203 PixelEditingContext::AvatarFrame(
204 avatar_id,
205 anim_id,
206 perspective_index,
207 frame_index,
208 ) => {
209 let avatar = self.avatars.get(avatar_id)?;
210 let anim = avatar.animations.iter().find(|a| a.id == *anim_id)?;
211 let perspective = anim.perspectives.get(*perspective_index)?;
212 perspective.frames.get(*frame_index)
213 }
214 _ => None,
215 }
216 }
217
218 pub fn get_editing_avatar_frame_mut(
220 &mut self,
221 editing_ctx: &PixelEditingContext,
222 ) -> Option<&mut rusterix::AvatarAnimationFrame> {
223 match editing_ctx {
224 PixelEditingContext::AvatarFrame(
225 avatar_id,
226 anim_id,
227 perspective_index,
228 frame_index,
229 ) => {
230 let avatar = self.avatars.get_mut(avatar_id)?;
231 let anim = avatar.animations.iter_mut().find(|a| a.id == *anim_id)?;
232 let perspective = anim.perspectives.get_mut(*perspective_index)?;
233 perspective.frames.get_mut(*frame_index)
234 }
235 _ => None,
236 }
237 }
238
239 pub fn get_editing_avatar_perspective(
241 &self,
242 editing_ctx: &PixelEditingContext,
243 ) -> Option<&rusterix::AvatarPerspective> {
244 match editing_ctx {
245 PixelEditingContext::AvatarFrame(avatar_id, anim_id, perspective_index, _) => {
246 let avatar = self.avatars.get(avatar_id)?;
247 let anim = avatar.animations.iter().find(|a| a.id == *anim_id)?;
248 anim.perspectives.get(*perspective_index)
249 }
250 _ => None,
251 }
252 }
253
254 pub fn get_editing_avatar_perspective_mut(
256 &mut self,
257 editing_ctx: &PixelEditingContext,
258 ) -> Option<&mut rusterix::AvatarPerspective> {
259 match editing_ctx {
260 PixelEditingContext::AvatarFrame(avatar_id, anim_id, perspective_index, _) => {
261 let avatar = self.avatars.get_mut(avatar_id)?;
262 let anim = avatar.animations.iter_mut().find(|a| a.id == *anim_id)?;
263 anim.perspectives.get_mut(*perspective_index)
264 }
265 _ => None,
266 }
267 }
268
269 pub fn add_item(&mut self, item: Item) {
271 self.items.insert(item.id, item);
272 }
273
274 pub fn remove_item(&mut self, id: &Uuid) {
276 self.items.shift_remove(id);
277 }
278
279 pub fn add_tilemap(&mut self, tilemap: Tilemap) {
281 self.tilemaps.push(tilemap)
282 }
283
284 pub fn get_tilemap(&self, uuid: Uuid) -> Option<&Tilemap> {
286 self.tilemaps.iter().find(|t| t.id == uuid)
287 }
288
289 pub fn get_tilemap_mut(&mut self, uuid: Uuid) -> Option<&mut Tilemap> {
291 self.tilemaps.iter_mut().find(|t| t.id == uuid)
292 }
293
294 pub fn remove_tilemap(&mut self, id: TheId) {
296 self.tilemaps.retain(|item| item.id != id.uuid);
297 }
298
299 pub fn contains_region(&self, uuid: &Uuid) -> bool {
301 self.regions.iter().find(|t| t.id == *uuid).is_some()
302 }
303
304 pub fn get_region(&self, uuid: &Uuid) -> Option<&Region> {
306 self.regions.iter().find(|t| t.id == *uuid)
307 }
308
309 pub fn get_region_mut(&mut self, uuid: &Uuid) -> Option<&mut Region> {
311 self.regions.iter_mut().find(|t| t.id == *uuid)
312 }
313
314 pub fn get_region_ctx(&self, ctx: &ServerContext) -> Option<&Region> {
316 self.regions.iter().find(|t| t.id == ctx.curr_region)
317 }
318
319 pub fn get_region_ctx_mut(&mut self, ctx: &ServerContext) -> Option<&mut Region> {
321 self.regions.iter_mut().find(|t| t.id == ctx.curr_region)
322 }
323
324 pub fn get_screen_ctx(&self, ctx: &ServerContext) -> Option<&Screen> {
326 self.screens.get(&ctx.curr_screen)
327 }
328
329 pub fn get_screen_ctx_mut(&mut self, ctx: &ServerContext) -> Option<&mut Screen> {
331 self.screens.get_mut(&ctx.curr_screen)
332 }
333
334 pub fn remove_region(&mut self, id: &Uuid) {
336 self.regions.retain(|item| item.id != *id);
337 }
338
339 pub fn get_map(&self, ctx: &ServerContext) -> Option<&Map> {
341 if ctx.editor_view_mode != EditorViewMode::D2 {
342 if let Some(region) = self.get_region(&ctx.curr_region) {
343 return Some(®ion.map);
344 }
345 } else if ctx.get_map_context() == MapContext::Region {
346 let id = ctx.curr_region;
347 if let Some(surface) = &ctx.editing_surface {
349 if let Some(region) = self.regions.iter().find(|t| t.id == id) {
350 if let Some(surface) = region.map.surfaces.get(&surface.id) {
351 if let Some(profile_id) = surface.profile {
352 return region.map.profiles.get(&profile_id);
353 }
354 }
355 }
356 return None;
357 } else if let Some(region) = self.regions.iter().find(|t| t.id == id) {
358 return Some(®ion.map);
359 }
360 } else if ctx.get_map_context() == MapContext::Screen {
362 if let Some(id) = ctx.pc.id() {
363 if let Some(screen) = self.screens.get(&id) {
364 return Some(&screen.map);
365 }
366 }
367 } else if ctx.get_map_context() == MapContext::Character {
368 if let ContentContext::CharacterTemplate(id) = ctx.curr_character {
369 if let Some(character) = self.characters.get(&id) {
370 return Some(&character.map);
371 }
372 }
373 } else if ctx.get_map_context() == MapContext::Item {
374 if let ContentContext::ItemTemplate(id) = ctx.curr_item {
375 if let Some(item) = self.items.get(&id) {
376 return Some(&item.map);
377 }
378 }
379 }
380 None
381 }
382
383 pub fn get_map_mut(&mut self, ctx: &ServerContext) -> Option<&mut Map> {
385 if ctx.get_map_context() == MapContext::Region {
386 let id = ctx.curr_region;
387 if ctx.editor_view_mode != EditorViewMode::D2 {
389 if let Some(region) = self.get_region_mut(&ctx.curr_region) {
390 return Some(&mut region.map);
391 }
392 } else if let Some(surface) = &ctx.editing_surface {
393 if let Some(region) = self.regions.iter_mut().find(|t| t.id == id) {
394 if let Some(surface) = region.map.surfaces.get_mut(&surface.id) {
395 if let Some(profile_id) = surface.profile {
396 return region.map.profiles.get_mut(&profile_id);
397 }
398 }
399 }
400 return None;
401 } else if let Some(region) = self.regions.iter_mut().find(|t| t.id == id) {
402 return Some(&mut region.map);
403 }
404 } else if ctx.get_map_context() == MapContext::Screen {
406 if let Some(id) = ctx.pc.id() {
407 if let Some(screen) = self.screens.get_mut(&id) {
408 return Some(&mut screen.map);
409 }
410 }
411 } else if ctx.get_map_context() == MapContext::Character {
412 if let ContentContext::CharacterTemplate(id) = ctx.curr_character {
413 if let Some(character) = self.characters.get_mut(&id) {
414 return Some(&mut character.map);
415 }
416 }
417 } else if ctx.get_map_context() == MapContext::Item {
418 if let ContentContext::ItemTemplate(id) = ctx.curr_item {
419 if let Some(item) = self.items.get_mut(&id) {
420 return Some(&mut item.map);
421 }
422 }
423 }
424 None
425 }
426
427 pub fn add_screen(&mut self, screen: Screen) {
429 self.screens.insert(screen.id, screen);
430 }
431
432 pub fn remove_screen(&mut self, id: &Uuid) {
434 self.screens.shift_remove(id);
435 }
436
437 pub fn sorted_screens_list(&self) -> Vec<(Uuid, String)> {
439 let mut entries: Vec<(Uuid, String)> = self
440 .screens
441 .iter()
442 .map(|(uuid, data)| (*uuid, data.name.clone()))
443 .collect();
444
445 entries.sort_by(|a, b| a.1.cmp(&b.1));
446 entries
447 }
448
449 pub fn add_asset(&mut self, asset: Asset) {
451 self.assets.insert(asset.id, asset);
452 }
453
454 pub fn remove_asset(&mut self, id: &Uuid) {
456 self.assets.shift_remove(id);
457 }
458
459 pub fn sorted_assets_list(&self) -> Vec<(Uuid, String)> {
461 let mut entries: Vec<(Uuid, String)> = self
462 .assets
463 .iter()
464 .map(|(uuid, data)| (*uuid, data.name.clone()))
465 .collect();
466
467 entries.sort_by(|a, b| a.1.cmp(&b.1));
468 entries
469 }
470
471 pub fn remove_tile(&mut self, id: &Uuid) {
473 for tilemap in &mut self.tilemaps {
474 tilemap.tiles.retain(|t| t.id != *id);
475 }
476 self.tiles.shift_remove(id);
477 }
478
479 pub fn get_tile(&self, id: &Uuid) -> Option<&Tile> {
481 for tilemap in &self.tilemaps {
482 for tile in &tilemap.tiles {
483 if tile.id == *id {
484 return Some(tile);
485 }
486 }
487 }
488 None
489 }
490
491 pub fn get_tile_mut(&mut self, id: &Uuid) -> Option<&mut Tile> {
493 for tilemap in &mut self.tilemaps {
494 for tile in &mut tilemap.tiles {
495 if tile.id == *id {
496 return Some(tile);
497 }
498 }
499 }
500 None
501 }
502
503 pub fn extract_tiles(&self) -> IndexMap<Uuid, TheRGBATile> {
505 let mut tiles = IndexMap::default();
506 for tilemap in &self.tilemaps {
507 for tile in &tilemap.tiles {
508 let mut rgba_tile = TheRGBATile::new();
509 rgba_tile.id = tile.id;
510 rgba_tile.name.clone_from(&tile.name);
511 rgba_tile.buffer = tilemap.buffer.extract_sequence(&tile.sequence);
512 rgba_tile.role = tile.role as u8;
513 rgba_tile.scale = tile.scale;
514 rgba_tile.render_mode = tile.render_mode;
515 rgba_tile.blocking = tile.blocking;
516 tiles.insert(tile.id, rgba_tile);
517 }
518 }
519 tiles
520 }
521
522 pub fn extract_tiles_vec(&self) -> Vec<TheRGBATile> {
524 let mut tiles = vec![];
525 for tilemap in &self.tilemaps {
526 for tile in &tilemap.tiles {
527 let mut rgba_tile = TheRGBATile::new();
528 rgba_tile.id = tile.id;
529 rgba_tile.name.clone_from(&tile.name);
530 rgba_tile.buffer = tilemap.buffer.extract_sequence(&tile.sequence);
531 rgba_tile.role = tile.role as u8;
532 tiles.push(rgba_tile);
533 }
534 }
535 tiles
536 }
537
538 pub fn extract_tile(&self, id: &Uuid) -> Option<TheRGBATile> {
540 for tilemap in &self.tilemaps {
541 for tile in &tilemap.tiles {
542 if tile.id == *id {
543 let mut rgba_tile = TheRGBATile::new();
544 rgba_tile.id = tile.id;
545 rgba_tile.name.clone_from(&tile.name);
546 rgba_tile.buffer = tilemap.buffer.extract_sequence(&tile.sequence);
547 rgba_tile.role = tile.role as u8;
548 return Some(rgba_tile);
549 }
550 }
551 }
552 None
553 }
554}