use bevy::asset::LoadedFolder;
use bevy::prelude::*;
use bevy::reflect::TypePath;
use serde::Deserialize;
use std::collections::HashMap;
pub struct ItemPlugin;
impl Plugin for ItemPlugin {
fn build(&self, app: &mut App) {
app.init_asset::<ItemAsset>()
.register_asset_loader(crate::core::ron_loader::RonAssetLoader::<ItemAsset>::new(
&["item.ron"],
))
.init_resource::<ItemRegistry>()
.add_systems(Startup, load_items_system)
.add_systems(Update, sync_items_system);
}
}
#[derive(Asset, TypePath, Debug, Deserialize)]
#[serde(transparent)]
pub struct ItemAsset(pub Vec<Item>);
#[derive(Debug, Clone, Deserialize, Reflect, PartialEq)]
pub struct ItemId(pub String);
#[derive(Debug, Clone, Deserialize, Reflect)]
pub struct Item {
pub id: String,
pub locate_name: String,
pub locate_file: String,
pub description: String,
pub item_type: ItemType,
}
#[derive(Debug, Clone, Deserialize, Reflect)]
pub enum ItemType {
Food {
consumable: bool,
effects: Vec<ItemEffect>,
},
Weapon {
damage: i32,
on_hit_effects: Vec<ItemEffect>,
},
Armor {
defense: i32,
},
}
#[derive(Debug, Clone, Deserialize, Reflect)]
pub enum ItemEffect {
Heal { amount: i32 },
PlayAudio { clip_path: String },
SpawnChildItem { item_id: String },
}
#[derive(Resource, Default)]
pub struct ItemRegistry(pub HashMap<String, Item>);
impl ItemRegistry {
pub fn get(&self, id: &str) -> Option<&Item> {
self.0.get(id)
}
}
#[derive(Resource)]
struct ItemFolderHandle(Handle<LoadedFolder>);
fn load_items_system(mut commands: Commands, asset_server: Res<AssetServer>) {
info!("Starting to load items from folder 'items'...");
let handle = asset_server.load_folder("shared/items");
commands.insert_resource(ItemFolderHandle(handle));
}
fn sync_items_system(
mut events: MessageReader<AssetEvent<LoadedFolder>>,
item_folder: Option<Res<ItemFolderHandle>>,
loaded_folders: Res<Assets<LoadedFolder>>,
item_assets: Res<Assets<ItemAsset>>,
mut registry: ResMut<ItemRegistry>,
) {
let Some(folder_handle) = item_folder else {
return;
};
for event in events.read() {
if let AssetEvent::LoadedWithDependencies { id } = event
&& *id == folder_handle.0.id()
{
info!("Item folder loaded. Indexing items...");
if let Some(folder) = loaded_folders.get(&folder_handle.0) {
for handle in &folder.handles {
let id = handle.id().typed::<ItemAsset>();
if let Some(asset) = item_assets.get(id) {
for item in &asset.0 {
info!("Registered Item: [{}] {}", item.id, item.locate_name);
registry.0.insert(item.id.clone(), item.clone());
}
}
}
}
info!(
"Item Registry initialization complete. Total items: {}",
registry.0.len()
);
}
}
}