Repository: NiklasEi/bevy_asset_loader (rust)

Issue:
Consider renaming `init_resource` to `then_init_resource`
- I am often confused when scanning my own code when I see `init_resource` because it's the same name as Bevy's `app.init_resource`, but it's slightly different.
- Ultimately it does end up initializing a resource, but I don't like that it's mixed in with the other function calls of my loading state when it's actually the last thing that is constructed after my loading state is ready.
- I note the docs for bevy_asset_loader's says:
> The resource will be initialized *at the end of the loading state* using its FromWorld implementation
- Therefore I can see the `then_` prefix flowing a bit better when reading a loading state.

Before:

```rust
app.add_loading_state(
    LoadingState::new(MyState::Preloading)
        .continue_to_state(MyState::Preloaded)
        .load_collection::<MyAssetCollection>()
        .load_collection::<MyAssetCollection2>()
        .init_resource::<MyResource>(),
);
```

After:

```rust
app.add_loading_state(
    LoadingState::new(MyState::Preloading)
        .continue_to_state(MyState::Preloaded)
        .load_collection::<MyAssetCollection>()
        .load_collection::<MyAssetCollection2>()
        .then_init_resource::<MyResource>(),
);
```

To me this reads clearer in that the resource is going to be initialised once all asset collections are loaded.

It could be even better if it was a bug to use a `then_init_resource` in the wrong position of the builder. For example, this wouldn't compile:

```rust
app.add_loading_state(
    LoadingState::new(MyState::Preloading)
        .continue_to_state(MyState::Preloaded)
        .then_init_resource::<MyResource>() // ERROR
        .load_collection::<MyAssetCollection>()
        .load_collection::<MyAssetCollection2>(),
);
```

Not sure what builder term you'd need to throw in there, maybe something like `collect` (shrug, don't love the term):

```rust
app.add_loading_state(
    LoadingState::new(MyState::Preloading)
        .continue_to_state(MyState::Preloaded)
        .load_collection::<MyAssetCollection>()
        .load_collection::<MyAssetCollection2>()
        .collect()
        .then_init_resource::<MyResource>(),
);
```

You might have some better ideas for a more fluent API here. E.g. maybe the argument to `add_loading_state` could remain as it is, but you can call `app.add_loading_state().when_ready_init_resource::<MyResource>()` instead.

P.S. Not sure if `then_init_resource` or `and_then_init_resource` would be better / more idiomatic.

If you prefer not to have a change like, feel free to close the issue, it's just some feedback from using the API here and it feeling a bit "messy", if I can say that.

Pull request description:
Rename init_resource on a loading state to finally_init_resource
Resolves #244

Also changes `finally_init_resource` to not overwrite existing resources of the same type. This follows Bevys behaviour of `init_resource`.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e80879..424e03d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,7 @@
 # Changelog
 
+- renamed `init_resource` to `finally_init_resource` to emphasise the difference to Bevy's `init_resource`
+
 ## v0.22.0 - 01.12.2024
 - support for Bevy 0.15
 - support for using sub states as loading states ([@mgi388](https://github.com/mgi388) in [#239](https://github.com/NiklasEi/bevy_asset_loader/pull/239))
diff --git a/README.md b/README.md
index fc15cc7..9ec009d 100644
--- a/README.md
+++ b/README.md
@@ -477,9 +477,9 @@ Any field in an asset collection without any attribute is required to implement
 
 ## Initializing FromWorld resources
 
-In situations where you would like to prepare other resources based on your loaded asset collections you can use `LoadingState::init_resource` or `LoadingStateConfig::init_resource` to initialize `FromWorld` resources. See [init_resource.rs](/bevy_asset_loader/examples/init_resource.rs) for an example that loads two images and then combines their pixel data into a third image.
+In situations where you would like to prepare other resources based on your loaded asset collections you can use `LoadingState::finally_init_resource` or `LoadingStateConfig::finally_init_resource` to initialize `FromWorld` resources. See [finally_init_resource.rs](/bevy_asset_loader/examples/finally_init_resource.rs) for an example that loads two images and then combines their pixel data into a third image.
 
-Both `init_resource` methods from `bevy_asset_loader` do the same as Bevy's `App::init_resource`, but at a different point in time. While Bevy inserts your resources at application startup, `bevy_asset_loader` will initialize them only after your asset collections are available. That means you can use your asset collections in the `FromWorld` implementation of the resource.
+Both `finally_init_resource` methods from `bevy_asset_loader` do the same as Bevy's `App::init_resource`, but at a different point in time. While Bevy inserts your resources at application startup, `bevy_asset_loader` will initialize them only after your asset collections are available. That means you can use your asset collections in the `FromWorld` implementation of the resource.
 
 ## Progress tracking
 
diff --git a/bevy_asset_loader/Cargo.toml b/bevy_asset_loader/Cargo.toml
index 83dddd2..a2bf5eb 100644
--- a/bevy_asset_loader/Cargo.toml
+++ b/bevy_asset_loader/Cargo.toml
@@ -57,8 +57,8 @@ path = "examples/atlas_from_grid.rs"
 required-features = ["2d"]
 
 [[example]]
-name = "init_resource"
-path = "examples/init_resource.rs"
+name = "finally_init_resource"
+path = "examples/finally_init_resource.rs"
 
 [[example]]
 name = "manual_dynamic_asset"
diff --git a/bevy_asset_loader/examples/README.md b/bevy_asset_loader/examples/README.md
index 15a69fb..f9e56fd 100644
--- a/bevy_asset_loader/examples/README.md
+++ b/bevy_asset_loader/examples/README.md
@@ -12,7 +12,7 @@ with `cargo run --example <example>`.
 | [`full_collection.rs`](full_collection.rs)                 | A complete asset collection with all supported non-dynamic field types   |
 | [`full_dynamic_collection.rs`](full_dynamic_collection.rs) | A complete asset collection with all supported dynamic asset field types |
 | [`image_asset.rs`](image_asset.rs)                         | How to set different samplers for image assets                           |
-| [`init_resource.rs`](init_resource.rs)                     | Inserting a `FromWorld` resource when all asset collections are loaded   |
+| [`finally_init_resource.rs`](finally_init_resource.rs)     | Inserting a `FromWorld` resource when all asset collections are loaded   |
 | [`manual_dynamic_asset.rs`](manual_dynamic_asset.rs)       | Load an image asset from a path resolved at run time                     |
 | [`no_loading_state.rs`](no_loading_state.rs)               | How to use asset collections without a loading state                     |
 | [`progress_tracking.rs`](progress_tracking.rs)             | How to set up progress tracking using `iyes_progress`                    |
diff --git a/bevy_asset_loader/examples/configure_loading_state.rs b/bevy_asset_loader/examples/configure_loading_state.rs
index 716ea9e..9819895 100644
--- a/bevy_asset_loader/examples/configure_loading_state.rs
+++ b/bevy_asset_loader/examples/configure_loading_state.rs
@@ -37,7 +37,7 @@ impl Plugin for PlayerAndMusicPlugin {
                 LoadingStateConfig::new(MyStates::AssetLoading)
                     .load_collection::<AudioAssets>()
                     .load_collection::<ImageAssets>()
-                    .init_resource::<ExampleResource>(),
+                    .finally_init_resource::<ExampleResource>(),
             );
     }
 }
diff --git a/bevy_asset_loader/examples/init_resource.rs b/bevy_asset_loader/examples/finally_init_resource.rs
similarity index 89%
rename from bevy_asset_loader/examples/init_resource.rs
rename to bevy_asset_loader/examples/finally_init_resource.rs
index c70fb2f..15f8cbe 100644
--- a/bevy_asset_loader/examples/init_resource.rs
+++ b/bevy_asset_loader/examples/finally_init_resource.rs
@@ -2,9 +2,9 @@ use bevy::ecs::system::SystemState;
 use bevy::prelude::*;
 use bevy_asset_loader::prelude::*;
 
-/// This example demonstrates how you can use [`LoadingState::init_resource`] to initialize
+/// This example demonstrates how you can use [`LoadingState::finally_init_resource`] to initialize
 /// assets implementing [`FromWorld`] after your collections are inserted into the ECS.
-/// The same is possible with [`LoadingStateConfig::init_resource`] from anywhere in your Bevy application
+/// The same is possible with [`LoadingStateConfig::finally_init_resource`] from anywhere in your Bevy application
 ///
 /// In this showcase we load two images in an [`AssetCollection`] and then combine
 /// them by adding up their pixel data.
@@ -16,7 +16,7 @@ fn main() {
             LoadingState::new(MyStates::AssetLoading)
                 .continue_to_state(MyStates::Next)
                 .load_collection::<ImageAssets>()
-                .init_resource::<CombinedImage>(),
+                .finally_init_resource::<CombinedImage>(),
         )
         .add_systems(OnEnter(MyStates::Next), draw)
         .run();
diff --git a/bevy_asset_loader/src/loading_state.rs b/bevy_asset_loader/src/loading_state.rs
index da2b020..aed9220 100644
--- a/bevy_asset_loader/src/loading_state.rs
+++ b/bevy_asset_loader/src/loading_state.rs
@@ -28,8 +28,8 @@ use dynamic_asset_systems::{
     resume_to_loading_asset_collections,
 };
 use systems::{
-    check_loading_collection, finish_loading_state, init_resource, initialize_loading_state,
-    reset_loading_state, resume_to_finalize, start_loading_collection,
+    check_loading_collection, finally_init_resource, finish_loading_state,
+    initialize_loading_state, reset_loading_state, resume_to_finalize, start_loading_collection,
 };
 
 #[cfg(feature = "standard_dynamic_assets")]
@@ -459,8 +459,8 @@ impl<S: FreelyMutableState> ConfigureLoadingState for LoadingState<S> {
         self
     }
 
-    fn init_resource<R: Resource + FromWorld>(mut self) -> Self {
-        self.config = self.config.init_resource::<R>();
+    fn finally_init_resource<R: Resource + FromWorld>(mut self) -> Self {
+        self.config = self.config.finally_init_resource::<R>();
 
         self
     }
@@ -477,6 +477,10 @@ impl<S: FreelyMutableState> ConfigureLoadingState for LoadingState<S> {
 
         self
     }
+
+    fn init_resource<R: Resource + FromWorld>(self) -> Self {
+        self.finally_init_resource::<R>()
+    }
 }
 
 ///  Systems in this set check the loading state of assets.
@@ -717,7 +721,7 @@ pub trait LoadingStateAppExt {
     ///           LoadingState::new(GameState::Loading)
     ///             .continue_to_state(GameState::Menu)
     ///             .load_collection::<TextureForAtlas>()
-    ///             .init_resource::<TextureAtlasLayoutFromWorld>()
+    ///             .finally_init_resource::<TextureAtlasLayoutFromWorld>()
     ///         )
     /// #       .set_runner(|mut app| {app.update(); AppExit::Success})
     /// #       .run();
@@ -748,7 +752,7 @@ pub trait LoadingStateAppExt {
     /// ```
     #[deprecated(
         since = "0.19.0",
-        note = "Use `LoadingState::init_resource` or `LoadingStateConfig::init_resource` instead."
+        note = "Use `LoadingState::finally_init_resource` or `LoadingStateConfig::finally_init_resource` instead."
     )]
     fn init_resource_after_loading_state<S: FreelyMutableState, A: Resource + FromWorld>(
         &mut self,
@@ -833,7 +837,7 @@ impl LoadingStateAppExt for App {
     ) -> &mut Self {
         self.add_systems(
             OnEnterInternalLoadingState(loading_state, InternalLoadingState::Finalize),
-            init_resource::<A>,
+            finally_init_resource::<A>,
         )
     }
 }
diff --git a/bevy_asset_loader/src/loading_state/config.rs b/bevy_asset_loader/src/loading_state/config.rs
index a1f6aac..4be4e8f 100644
--- a/bevy_asset_loader/src/loading_state/config.rs
+++ b/bevy_asset_loader/src/loading_state/config.rs
@@ -4,7 +4,7 @@ use crate::loading_state::dynamic_asset_systems::{
     check_dynamic_asset_collections, load_dynamic_asset_collections,
 };
 use crate::loading_state::systems::{
-    check_loading_collection, init_resource, start_loading_collection,
+    check_loading_collection, finally_init_resource, start_loading_collection,
 };
 use crate::loading_state::{
     InternalLoadingState, InternalLoadingStateSet, LoadingStateSchedule,
@@ -32,9 +32,9 @@ pub trait ConfigureLoadingState {
     /// The resource will be initialized at the end of the loading state using its [`FromWorld`] implementation.
     /// All asset collections will be available at that point and fully loaded.
     ///
-    /// See the `init_resource` example
+    /// See the `finally_init_resource` example
     #[must_use = "The configuration will only be applied when passed to App::configure_loading_state"]
-    fn init_resource<R: Resource + FromWorld>(self) -> Self;
+    fn finally_init_resource<R: Resource + FromWorld>(self) -> Self;
 
     /// Register a custom dynamic asset collection type
     ///
@@ -48,6 +48,17 @@ pub trait ConfigureLoadingState {
     /// See the `dynamic_asset` example
     #[must_use = "The configuration will only be applied when passed to App::configure_loading_state"]
     fn with_dynamic_assets_file<C: DynamicAssetCollection + Asset>(self, file: &str) -> Self;
+
+    /// The resource will be initialized at the end of the loading state using its [`FromWorld`] implementation.
+    /// All asset collections will be available at that point and fully loaded.
+    ///
+    /// See the `finally_init_resource` example
+    #[must_use = "The configuration will only be applied when passed to App::configure_loading_state"]
+    #[deprecated(
+        since = "0.22.1",
+        note = "Method has been renamed to `finally_init_resource`"
+    )]
+    fn init_resource<R: Resource + FromWorld>(self) -> Self;
 }
 
 /// Can be used to add new asset collections or similar configuration to a loading state.
@@ -169,9 +180,9 @@ impl<S: FreelyMutableState> ConfigureLoadingState for LoadingStateConfig<S> {
         self
     }
 
-    fn init_resource<R: Resource + FromWorld>(mut self) -> Self {
+    fn finally_init_resource<R: Resource + FromWorld>(mut self) -> Self {
         self.on_enter_finalize
-            .push(init_resource::<R>.into_configs());
+            .push(finally_init_resource::<R>.into_configs());
 
         self
     }
@@ -192,4 +203,8 @@ impl<S: FreelyMutableState> ConfigureLoadingState for LoadingStateConfig<S> {
 
         self
     }
+
+    fn init_resource<R: Resource + FromWorld>(self) -> Self {
+        self.finally_init_resource::<R>()
+    }
 }
diff --git a/bevy_asset_loader/src/loading_state/systems.rs b/bevy_asset_loader/src/loading_state/systems.rs
index 3f74bc2..1d219d7 100644
--- a/bevy_asset_loader/src/loading_state/systems.rs
+++ b/bevy_asset_loader/src/loading_state/systems.rs
@@ -16,9 +16,8 @@ use iyes_progress::{ProgressEntryId, ProgressTracker};
 use std::any::{type_name, TypeId};
 use std::marker::PhantomData;
 
-pub(crate) fn init_resource<Asset: Resource + FromWorld>(world: &mut World) {
-    let asset = Asset::from_world(world);
-    world.insert_resource(asset);
+pub(crate) fn finally_init_resource<Asset: Resource + FromWorld>(world: &mut World) {
+    world.init_resource::<Asset>();
 }
 
 #[allow(clippy::type_complexity)]


Test patch:
diff --git a/bevy_asset_loader/tests/init_resource.rs b/bevy_asset_loader/tests/finally_init_resource.rs
similarity index 95%
rename from bevy_asset_loader/tests/init_resource.rs
rename to bevy_asset_loader/tests/finally_init_resource.rs
index c8775b3..fded0c1 100644
--- a/bevy_asset_loader/tests/init_resource.rs
+++ b/bevy_asset_loader/tests/finally_init_resource.rs
@@ -6,7 +6,7 @@ use bevy::state::app::StatesPlugin;
 use bevy_asset_loader::prelude::*;
 
 #[test]
-fn init_resource() {
+fn finally_init_resource() {
     let mut app = App::new();
 
     app.add_plugins((
@@ -20,7 +20,7 @@ fn init_resource() {
         LoadingState::new(MyStates::Load)
             .continue_to_state(MyStates::Next)
             .load_collection::<MyAssets>()
-            .init_resource::<PostProcessed>(),
+            .finally_init_resource::<PostProcessed>(),
     )
     .add_systems(Update, timeout.run_if(in_state(MyStates::Load)))
     .add_systems(OnEnter(MyStates::Next), expect)