Skip to content

Commit

Permalink
0.4.0 (#4)
Browse files Browse the repository at this point in the history
# **BREAKING CHANGE**
It is no longer necessary to prepend the main folder where the assets
are located when using `FontAssetList`.

If you were doing

```rust
app.insert_resource(FontAssetList::new(
    [
        "fonts/bold.ttf",
        "fonts/italic.ttf",
        "fonts/thin.ttf",
    ]
    .into(),
));
```

change this to

```rust
app.insert_resource(FontAssetList::new(
    [
        "bold.ttf",
        "italic.ttf",
        "thin.ttf",
    ]
    .into(),
));
```

The folder will be taken from the `FontAssetFolder` Resource.

# What was done
- Fixed issues that caused the plugin to hang forever in a `NotLoaded`
state.
- Refactored the plugin code.
- Updated README and added documentation for public types.
  • Loading branch information
mnmaita authored Aug 22, 2024
1 parent d6191bf commit 08cc955
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 73 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "trve_bevy_font"
version = "0.3.0"
version = "0.4.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
32 changes: 24 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ trve_bevy_font = { git = "https://github.com/mnmaita/trve_bevy_font" }
Remember you can also target tags, commits and branches with this method:

```toml
trve_bevy_font = { git = "https://github.com/mnmaita/trve_bevy_font", tag = "v0.3.0" }
trve_bevy_font = { git = "https://github.com/mnmaita/trve_bevy_font", tag = "v0.4.0" }
```

```toml
Expand Down Expand Up @@ -45,25 +45,41 @@ This will load all assets from `assets/ttfs` by using `AssetServer`'s `load_fold

### Loading a list of assets

Certain platforms, like web, can't use `load_folder` to load assets so this library provides an override via the `FontAssetList` Resource. This allows you to load a list of assets from your `assets` folder.
Certain platforms, like web, can't use `load_folder` to load assets so this library provides an override via the `FontAssetList` Resource.

```rs
This allows you to load a list of assets from the folder specified in the `FontAssetFolder` Resource, within the `assets` directory.

```rust
// This will attempt to load `assets/fonts/bold.ttf`, `assets/fonts/italic.ttf` and `assets/fonts/thin.ttf`.
app.insert_resource(FontAssetList::new(
[
"bold.ttf",
"italic.ttf",
"thin.ttf",
]
.into(),
));
```

```rust
// This will attempt to load `assets/ttfs/bold.ttf`, `assets/ttfs/italic.ttf` and `assets/ttfs/thin.ttf`.
app.insert_resource(FontAssetFolder::new("ttfs"));
app.insert_resource(FontAssetList::new(
[
"typography/bold.ttf",
"typography/italic.ttf",
"typography/thin.ttf",
"bold.ttf",
"italic.ttf",
"thin.ttf",
]
.into(),
));
```

If you insert this Resource, `FontAssetFolder` will be ignored and the plugin will only load assets based on the provided list.
If you insert this Resource the plugin will **only** load the assets provided in the list.

## Bevy version compatibility

| trve_bevy_font | bevy |
| -------------- | ---- |
| 0.3 | 0.14 |
| 0.3 0.4 | 0.14 |
| 0.2 | 0.13 |
| 0.1 | 0.12 |
165 changes: 101 additions & 64 deletions src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,24 @@ pub struct TrveFontPlugin;

impl Plugin for TrveFontPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<FontAssetFolder>();
app.init_resource::<FontLoadState>();
app.add_systems(Startup, load_fonts);
app.add_systems(
Startup,
(setup_resources, load_fonts.after(setup_resources)),
);
app.add_systems(
Update,
update_font_assets_load_state.run_if(not(resource_equals(FontLoadState::Loaded))),
update_font_assets_load_state.run_if(not(resource_equals(FontLoadState::LOADED))),
);
}
}

/// Determines the name of the directory (within the `assets` directory) from where fonts will be loaded.
///
/// By default, this is set to "fonts".
///
/// Since `AssetServer::load_folder()` is unsupported in web builds, it will only be used as the base
/// directory for the file names in the `FontAssetList` Resource.
#[derive(Resource)]
pub struct FontAssetFolder<'a>(AssetPath<'a>);

Expand All @@ -28,43 +36,60 @@ impl<'a> FontAssetFolder<'a> {
}
}

impl Default for FontAssetFolder<'_> {
fn default() -> Self {
Self(FONT_ASSET_FOLDER.into())
}
}

impl std::fmt::Display for FontAssetFolder<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}

/// List of assets to be loaded from the directory specified in the `FontAssetFolder` Resource.
///
/// Should be a list of file names with their extension.
///
/// This works as an override for `FontAssetFolder` in non-web platforms so, if set,
/// assets will be loaded individually and only from this list.
///
/// In web builds this is the default and the only supported option.
///
/// Example:
///
/// ```
/// app.insert_resource(FontAssetList::new(
/// [
/// "font1.ttf",
/// "font2.ttf",
/// "font3.ttf",
/// ]
/// .to_vec(),
/// ));
/// ```
#[derive(Resource, Default, Deref)]
pub struct FontAssetList<'a>(Vec<AssetPath<'a>>);

impl<'a> FontAssetList<'a> {
pub fn new(path: Vec<impl Into<AssetPath<'a>>>) -> Self {
Self(
path.into_iter()
.map(|path| path.into())
.collect::<Vec<AssetPath<'a>>>(),
)
pub fn new(paths: Vec<impl Into<AssetPath<'a>>>) -> Self {
let asset_paths: Vec<AssetPath<'a>> = paths.into_iter().map(|path| path.into()).collect();
Self(asset_paths)
}
}

impl Default for FontAssetFolder<'_> {
#[derive(Resource, PartialEq, Deref)]
struct FontLoadState(RecursiveDependencyLoadState);

impl Default for FontLoadState {
fn default() -> Self {
Self(FONT_ASSET_FOLDER.into())
Self(RecursiveDependencyLoadState::NotLoaded)
}
}

#[derive(Default, Resource, PartialEq)]
enum FontLoadState {
#[default]
NotLoaded,
Loading,
Loaded,
Failed,
}

impl From<RecursiveDependencyLoadState> for FontLoadState {
fn from(value: RecursiveDependencyLoadState) -> Self {
match value {
RecursiveDependencyLoadState::NotLoaded => Self::NotLoaded,
RecursiveDependencyLoadState::Loading => Self::Loading,
RecursiveDependencyLoadState::Loaded => Self::Loaded,
RecursiveDependencyLoadState::Failed => Self::Failed,
}
}
impl FontLoadState {
const LOADED: Self = Self(RecursiveDependencyLoadState::Loaded);
}

#[derive(Resource, Default, Deref, DerefMut)]
Expand All @@ -73,34 +98,37 @@ struct FontHandles(Vec<Handle<Font>>);
#[derive(Resource, Default, Deref, DerefMut)]
struct FontFolderHandle(Handle<LoadedFolder>);

fn setup_resources(mut commands: Commands) {
commands.init_resource::<FontAssetFolder>();

if cfg!(target_family = "wasm") {
commands.init_resource::<FontAssetList>();
}
}

fn load_fonts(
mut commands: Commands,
asset_server: Res<AssetServer>,
font_folder: Res<FontAssetFolder<'static>>,
font_asset_list: Option<Res<FontAssetList<'static>>>,
) {
if cfg!(not(target_family = "wasm")) && font_asset_list.is_none() {
commands.insert_resource(FontFolderHandle(
asset_server.load_folder(font_folder.0.clone()),
));
return;
if cfg!(not(target_family = "wasm")) {
if font_asset_list.is_none() {
// TODO: Verify that files in the directory are actually Font handles
commands.insert_resource(FontFolderHandle(
asset_server.load_folder(font_folder.0.clone()),
));
return;
}
}

if let Some(font_asset_list) = font_asset_list {
if font_asset_list.is_empty() {
if cfg!(target_family = "wasm") {
info!("FontAssetList Resource is empty.");
}
} else {
commands.insert_resource(FontHandles(
font_asset_list
.iter()
.map(|path| asset_server.load::<Font>(path))
.collect::<Vec<Handle<Font>>>(),
));
}
} else if cfg!(target_family = "wasm") {
warn!("FontAssetList Resource does not exist.");
let load_font_asset = |path| asset_server.load::<Font>(format!("{}/{path}", *font_folder));
let handles: Vec<Handle<Font>> = match font_asset_list.is_empty() {
true => Vec::default(),
false => font_asset_list.iter().map(load_font_asset).collect(),
};
commands.insert_resource(FontHandles(handles));
}
}

Expand All @@ -111,25 +139,34 @@ fn update_font_assets_load_state(
font_folder_handle: Option<Res<FontFolderHandle>>,
font_asset_list: Option<Res<FontAssetList<'static>>>,
) {
if font_asset_list.is_some() {
if let Some(font_handles) = font_handles {
let all_loaded = font_handles.iter().all(|handle| {
asset_server.recursive_dependency_load_state(handle.id())
== RecursiveDependencyLoadState::Loaded
});
*font_load_state = if all_loaded {
RecursiveDependencyLoadState::Loaded.into()
} else {
RecursiveDependencyLoadState::NotLoaded.into()
}
if cfg!(not(target_family = "wasm")) {
if font_asset_list.is_none() {
font_load_state.0 =
asset_server.recursive_dependency_load_state(&font_folder_handle.unwrap().0);
return;
}
} else if let Some(font_folder_handle) = font_folder_handle {
*font_load_state = asset_server
.recursive_dependency_load_state(&font_folder_handle.0)
.into()
}

if let Some(font_handles) = font_handles {
let all_loaded = font_handles.iter().all(|handle| {
if RecursiveDependencyLoadState::Failed
== asset_server.recursive_dependency_load_state(handle)
{
if let Some(path) = handle.path() {
info!("Asset '{path}' failed to load. Make sure the file name is correct and is a font.");
}
return true;
}
asset_server.is_loaded_with_dependencies(handle)
});

font_load_state.0 = match all_loaded {
true => RecursiveDependencyLoadState::Loaded,
false => RecursiveDependencyLoadState::NotLoaded,
};
}
}

pub fn font_assets_loaded() -> impl Condition<()> {
IntoSystem::into_system(resource_equals(FontLoadState::Loaded))
IntoSystem::into_system(resource_equals(FontLoadState::LOADED))
}

0 comments on commit 08cc955

Please sign in to comment.