From 8129e5564e52cbe971efe36e0d33fdb5a2b316fa Mon Sep 17 00:00:00 2001 From: Trevor Lovell Date: Sat, 14 Oct 2023 12:00:51 -0600 Subject: [PATCH] feat: add level locale types and begin splitting internal_levels and external_levels features (#237) As part of the rework of the asset types, it is useful to be able to define types that are generic over the "level locale" of the project they represent. The terminology level locale refers to whether or not the project uses internal levels (level data embedded in the main project asset) or external levels (level data stored in separate individual-level files). Such a generic type is able to define different implementations of the same trait for the two locales, or the same implementation of the same trait, or even completely different methods between the two locales. To facilitate this, this PR adds a `LevelLocale` trait, which is mostly a marker trait implemented by the new `InternalLevels` and `ExternalLevels` unit structs. It does provide an associated type to the sort of level metadata that is created for the two locales, but other than that it will mostly be used as a trait bound for generic types. The fact that the trait is private means that users will not be able to create new locales that don't fit into the canonical asset type design defined here. This also introduces the `internal_levels` and `external_levels` features. These two features are not mutually exclusive, but at least one of them does need to be enabled. The eventual asset type design will hide most things behind these features so users can slightly optimize their compilation if they want to. (Ignore broken doc-links here, they will no longer be broken in future PRs) --- .github/workflows/lint.yml | 6 +++-- Cargo.toml | 4 ++- src/assets/level_indices.rs | 4 ++- src/assets/level_locale.rs | 48 ++++++++++++++++++++++++++++++++++++ src/assets/level_metadata.rs | 15 ++++++----- src/assets/mod.rs | 14 ++++++++++- src/lib.rs | 7 +++++- 7 files changed, 84 insertions(+), 14 deletions(-) create mode 100644 src/assets/level_locale.rs diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8cc9abda..df9d37ab 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -31,8 +31,10 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: Install Dependencies run: sudo apt-get update; sudo apt-get install pkg-config libx11-dev libasound2-dev libudev-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev - - name: Run cargo check (no features, exclude examples) - run: cargo check --no-default-features + - name: Run cargo check (minimal features, internal levels, exclude examples) + run: cargo check --no-default-features --features internal_levels + - name: Run cargo check (minimal features, external levels, exclude examples) + run: cargo check --no-default-features --features external_levels - name: Run cargo check (default features) run: cargo check --all-targets - name: Run cargo check (all features) diff --git a/Cargo.toml b/Cargo.toml index 3fd02e84..253befdd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,10 +33,12 @@ rand = "0.8" bevy-inspector-egui = "0.19.0" [features] -default = ["derive", "render"] +default = ["derive", "render", "internal_levels"] derive = ["bevy_ecs_ldtk_macros"] atlas = ["bevy_ecs_tilemap/atlas"] render = ["bevy_ecs_tilemap/render"] +internal_levels = [] +external_levels = [] [[example]] name = "platformer" diff --git a/src/assets/level_indices.rs b/src/assets/level_indices.rs index 08240977..af894c8b 100644 --- a/src/assets/level_indices.rs +++ b/src/assets/level_indices.rs @@ -1,3 +1,5 @@ +use bevy::reflect::Reflect; + /// Indices pointing to the location of a level in an [`LdtkProject`] or [`LdtkJson`]. /// /// This type supports multi-world projects by storing an optional `world` index. @@ -6,7 +8,7 @@ /// /// [`LdtkProject`]: crate::assets::LdtkProject /// [`LdtkJson`]: crate::ldtk::LdtkJson -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Reflect)] pub struct LevelIndices { /// The index of the world the level belongs to, if the project is multi-world. pub world: Option, diff --git a/src/assets/level_locale.rs b/src/assets/level_locale.rs new file mode 100644 index 00000000..a5416341 --- /dev/null +++ b/src/assets/level_locale.rs @@ -0,0 +1,48 @@ +use bevy::reflect::Reflect; + +#[cfg(feature = "internal_levels")] +use crate::assets::LevelMetadata; + +#[cfg(feature = "external_levels")] +use crate::assets::ExternalLevelMetadata; + +/// Trait for marker types describing the location of levels. +/// +/// Used as a trait bound to parameterize [`LdtkJsonWithMetadata`]. +/// Also provides an associated type defining the level metadata type for the locale. +/// +/// Only implemented by [`InternalLevels`] and [`ExternalLevels`]. +/// +/// [`LdtkJsonWithMetadata`]: crate::assets::LdtkJsonWithMetadata +pub trait LevelLocale { + /// Level metadata type used for this locale. + type Metadata; +} + +#[cfg(feature = "internal_levels")] +/// Marker type for indicating an internal-levels LDtk project. +/// +/// Used to parameterize [`LdtkJsonWithMetadata`]. +/// +/// [`LdtkJsonWithMetadata`]: crate::assets::LdtkJsonWithMetadata +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Reflect)] +pub struct InternalLevels; + +#[cfg(feature = "internal_levels")] +impl LevelLocale for InternalLevels { + type Metadata = LevelMetadata; +} + +#[cfg(feature = "external_levels")] +/// Marker type for indicating an external-levels LDtk projects. +/// +/// Used to parameterize [`LdtkJsonWithMetadata`]. +/// +/// [`LdtkJsonWithMetadata`]: crate::assets::LdtkJsonWithMetadata +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Reflect)] +pub struct ExternalLevels; + +#[cfg(feature = "external_levels")] +impl LevelLocale for ExternalLevels { + type Metadata = ExternalLevelMetadata; +} diff --git a/src/assets/level_metadata.rs b/src/assets/level_metadata.rs index c7cf9345..ae454e82 100644 --- a/src/assets/level_metadata.rs +++ b/src/assets/level_metadata.rs @@ -1,17 +1,14 @@ use crate::assets::LevelIndices; -use bevy::{ - prelude::*, - reflect::{TypePath, TypeUuid}, -}; +use bevy::{prelude::*, reflect::Reflect}; use derive_getters::Getters; +#[cfg(feature = "external_levels")] use crate::assets::LdtkLevel; /// Metadata produced for every level during [`LdtkProject`] loading. /// /// [`LdtkProject`]: crate::assets::LdtkProject -#[derive(Clone, Debug, Default, Eq, PartialEq, TypeUuid, TypePath, Getters)] -#[uuid = "bba47e30-5036-4994-acde-d62a440b16b8"] +#[derive(Clone, Debug, Default, Eq, PartialEq, Getters, Reflect)] pub struct LevelMetadata { /// Image handle for the background image of this level, if it has one. bg_image: Option>, @@ -26,11 +23,11 @@ impl LevelMetadata { } } +#[cfg(feature = "external_levels")] /// Metadata produced for every level during [`LdtkProject`] loading for external-levels projects. /// /// [`LdtkProject`]: crate::assets::LdtkProject -#[derive(Clone, Debug, Default, Eq, PartialEq, TypeUuid, TypePath, Getters)] -#[uuid = "d3190ad4-6fa4-4f47-b15b-87f92f191738"] +#[derive(Clone, Debug, Default, Eq, PartialEq, Getters, Reflect)] pub struct ExternalLevelMetadata { /// Common metadata for this level. metadata: LevelMetadata, @@ -38,6 +35,7 @@ pub struct ExternalLevelMetadata { external_handle: Handle, } +#[cfg(feature = "external_levels")] impl ExternalLevelMetadata { /// Construct a new [`ExternalLevelMetadata`]. pub fn new(metadata: LevelMetadata, external_handle: Handle) -> Self { @@ -73,6 +71,7 @@ mod tests { assert_eq!(*level_metadata.indices(), LevelIndices::in_world(2, 3)); } + #[cfg(feature = "external_levels")] #[test] fn external_level_metadata_construction() { let level_metadata = LevelMetadata::new(None, LevelIndices::in_root(1)); diff --git a/src/assets/mod.rs b/src/assets/mod.rs index a416be3c..7b7dfa5d 100644 --- a/src/assets/mod.rs +++ b/src/assets/mod.rs @@ -7,7 +7,19 @@ mod ldtk_asset_plugin; pub use ldtk_asset_plugin::LdtkAssetPlugin; mod level_metadata; -pub use level_metadata::{ExternalLevelMetadata, LevelMetadata}; + +pub use level_metadata::LevelMetadata; + +#[cfg(feature = "external_levels")] +pub use level_metadata::ExternalLevelMetadata; + +mod level_locale; + +#[cfg(feature = "internal_levels")] +pub use level_locale::InternalLevels; + +#[cfg(feature = "external_levels")] +pub use level_locale::ExternalLevels; mod level_metadata_accessor; pub use level_metadata_accessor::LevelMetadataAccessor; diff --git a/src/lib.rs b/src/lib.rs index f2e3054e..2ba1ec4b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,13 +99,18 @@ //! ### Feature flags //! //! This crate uses the following set of [feature flags]: +//! - `internal_levels`: Enable support for projects that store levels internally. +//! I.e., projects that store level data within the main project file. +//! - `external_levels`: Enable support for projects that store levels externally. +//! I.e., projects that store data for each level in files separate from the main project file. //! - `derive`: Enables the derive macros for [LdtkEntity] and [LdtkIntCell]. //! - `render`: Enables rendering via [bevy_ecs_tilemap]'s `render` feature. Disable it if you want //! to run in headless mode. //! - `atlas`: Enables the `atlas` feature of [bevy_ecs_tilemap]. This is required for WASM support //! and also for tile spacing to work on Tile and AutoTile layers. //! -//! The `derive` and `render` features are enabled by default. +//! The `derive`, `render`, and `internal_levels` features are enabled by default. +//! Furthermore, one or both of `internal_levels` and `external_levels` must be enabled. //! //! [App]: bevy::prelude::App //! [Commands]: bevy::prelude::Commands