use crate::ldtk::{
ldtk_fields::LdtkFields, BgPos, FieldInstance, LayerInstance, Level, LevelBackgroundPosition,
NeighbourLevel,
};
use bevy::prelude::Color;
use thiserror::Error;
#[derive(Debug, Error)]
#[error("loaded levels must have non-null layer instances")]
pub struct LevelNotLoaded;
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct LoadedLevel<'a> {
level: &'a Level,
}
impl<'a> TryFrom<&'a Level> for LoadedLevel<'a> {
type Error = LevelNotLoaded;
fn try_from(level: &'a Level) -> Result<Self, Self::Error> {
if level.layer_instances.is_some() {
Ok(LoadedLevel { level })
} else {
Err(LevelNotLoaded)
}
}
}
impl<'a> LoadedLevel<'a> {
pub fn raw(&self) -> &'a Level {
self.level
}
pub fn bg_color(&self) -> &'a Color {
&self.level.bg_color
}
pub fn bg_pos(&self) -> &'a Option<LevelBackgroundPosition> {
&self.level.bg_pos
}
pub fn neighbours(&self) -> &'a Vec<NeighbourLevel> {
&self.level.neighbours
}
pub fn smart_color(&self) -> &'a Color {
&self.level.smart_color
}
pub fn level_bg_color(&self) -> &'a Option<Color> {
&self.level.level_bg_color
}
pub fn bg_pivot_x(&self) -> &'a f32 {
&self.level.bg_pivot_x
}
pub fn bg_pivot_y(&self) -> &'a f32 {
&self.level.bg_pivot_y
}
pub fn level_bg_pos(&self) -> &'a Option<BgPos> {
&self.level.level_bg_pos
}
pub fn bg_rel_path(&self) -> &'a Option<String> {
&self.level.bg_rel_path
}
pub fn external_rel_path(&self) -> &'a Option<String> {
&self.level.external_rel_path
}
pub fn field_instances(&self) -> &'a Vec<FieldInstance> {
&self.level.field_instances
}
pub fn identifier(&self) -> &'a String {
&self.level.identifier
}
pub fn iid(&self) -> &'a String {
&self.level.iid
}
pub fn layer_instances(&self) -> &'a Vec<LayerInstance> {
self.level
.layer_instances
.as_ref()
.expect("LoadedLevel construction should guarantee the existence of layer instances")
}
pub fn px_hei(&self) -> &'a i32 {
&self.level.px_hei
}
pub fn px_wid(&self) -> &'a i32 {
&self.level.px_wid
}
pub fn uid(&self) -> &'a i32 {
&self.level.uid
}
pub fn use_auto_identifier(&self) -> &'a bool {
&self.level.use_auto_identifier
}
pub fn world_depth(&self) -> &'a i32 {
&self.level.world_depth
}
pub fn world_x(&self) -> &'a i32 {
&self.level.world_x
}
pub fn world_y(&self) -> &'a i32 {
&self.level.world_y
}
}
impl LdtkFields for LoadedLevel<'_> {
fn field_instances(&self) -> &[FieldInstance] {
self.level.field_instances()
}
}
#[cfg(test)]
mod tests {
use bevy::color::palettes::css;
use super::*;
fn valid_level() -> Level {
Level {
bg_color: css::AZURE.into(),
bg_pos: Some(LevelBackgroundPosition::default()),
neighbours: vec![NeighbourLevel::default()],
smart_color: css::BEIGE.into(),
level_bg_color: Some(css::AQUA.into()),
bg_pivot_x: 0.,
bg_pivot_y: 1.,
level_bg_pos: Some(BgPos::Cover),
bg_rel_path: Some("path/to/bg.png".to_string()),
external_rel_path: Some("path/to/external.ldtkl".to_string()),
field_instances: vec![],
identifier: "level_identifier".to_string(),
iid: "level_iid".to_string(),
layer_instances: Some(vec![LayerInstance::default()]),
px_hei: 2,
px_wid: 3,
uid: 4,
use_auto_identifier: true,
world_depth: 5,
world_x: 6,
world_y: 7,
}
}
#[test]
fn getter_methods_return_correct_values() {
let raw = valid_level();
let loaded = LoadedLevel::try_from(&raw).unwrap();
assert_eq!(*loaded.layer_instances(), vec![LayerInstance::default()]);
assert_eq!(*loaded.bg_color(), css::AZURE.into());
assert_eq!(*loaded.bg_pos(), Some(LevelBackgroundPosition::default()));
assert_eq!(*loaded.neighbours(), vec![NeighbourLevel::default()]);
assert_eq!(*loaded.smart_color(), css::BEIGE.into());
assert_eq!(*loaded.level_bg_color(), Some(css::AQUA.into()));
assert_eq!(*loaded.bg_pivot_x(), 0.);
assert_eq!(*loaded.bg_pivot_y(), 1.);
assert_eq!(*loaded.level_bg_pos(), Some(BgPos::Cover));
assert_eq!(*loaded.bg_rel_path(), Some("path/to/bg.png".to_string()));
assert_eq!(
*loaded.external_rel_path(),
Some("path/to/external.ldtkl".to_string())
);
assert_eq!(*loaded.field_instances(), vec![]);
assert_eq!(*loaded.identifier(), "level_identifier".to_string());
assert_eq!(*loaded.iid(), "level_iid".to_string());
assert_eq!(*loaded.px_hei(), 2);
assert_eq!(*loaded.px_wid(), 3);
assert_eq!(*loaded.uid(), 4);
assert!(*loaded.use_auto_identifier());
assert_eq!(*loaded.world_depth(), 5);
assert_eq!(*loaded.world_x(), 6);
assert_eq!(*loaded.world_y(), 7);
}
#[test]
fn cannot_create_from_unloaded_level() {
let mut raw = valid_level();
raw.layer_instances = None;
assert!(matches!(LoadedLevel::try_from(&raw), Err(LevelNotLoaded)));
}
}