use crate::core::item::ItemId;
use crate::core::player_components::{
Equipment, Gold, Health, Inventory, Level, PlayerBundle, PlayerName, Stats,
};
use bevy::app::{App, Plugin, Startup, Update};
use bevy::prelude::{
Added, Changed, Commands, Component, IntoScheduleConfigs, Name, Or, Query, ResMut, Resource,
With,
};
pub(crate) struct DataPlugin;
impl Plugin for DataPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<PlayerData>()
.add_systems(Startup, spawn_player_entity_system)
.add_systems(
Update,
sync_player_entity_to_resource_system.run_if(player_entity_changed),
);
}
}
#[derive(Component)]
pub struct MainPlayer;
fn spawn_player_entity_system(mut commands: Commands) {
commands.spawn((PlayerBundle::new(), MainPlayer, Name::new("Player")));
}
type PlayerChangedFilter = (
With<MainPlayer>,
Or<(
Changed<PlayerName>,
Changed<Level>,
Changed<Health>,
Changed<Stats>,
Changed<Gold>,
Changed<Equipment>,
Changed<Inventory>,
Added<MainPlayer>,
)>,
);
fn player_entity_changed(query: Query<(), PlayerChangedFilter>) -> bool {
!query.is_empty()
}
type PlayerComponentsQuery<'w, 's> = Query<
'w,
's,
(
&'static PlayerName,
&'static Level,
&'static Health,
&'static Stats,
&'static Gold,
&'static Equipment,
&'static Inventory,
),
With<MainPlayer>,
>;
fn sync_player_entity_to_resource_system(
query: PlayerComponentsQuery,
mut player_data: ResMut<PlayerData>,
) {
let Ok((name, level, health, stats, gold, equipment, inventory)) = query.single() else {
return;
};
player_data.name = name.0.clone();
player_data.lv = level.lv;
player_data.exp = level.exp;
player_data.next_exp = level.next_exp;
player_data.hp = health.current;
player_data.hp_max = health.max;
player_data.attack = stats.attack;
player_data.defense = stats.defense;
player_data.gold = gold.0;
player_data.weapon = equipment.weapon.clone();
player_data.armor = equipment.armor.clone();
player_data.inventory = inventory.items.clone();
player_data.inventory_capacity = inventory.capacity;
}
#[derive(Resource)]
pub(crate) struct PlayerData {
pub(crate) name: String,
pub(crate) lv: usize,
pub(crate) exp: usize,
pub(crate) next_exp: usize,
pub(crate) hp: usize,
pub(crate) hp_max: usize,
pub(crate) attack: usize,
pub(crate) defense: usize,
pub(crate) gold: usize,
pub(crate) weapon: ItemId,
pub(crate) armor: ItemId,
pub(crate) inventory: Vec<ItemId>,
pub(crate) inventory_capacity: usize,
}
impl Default for PlayerData {
fn default() -> Self {
PlayerData {
name: "Chara".to_string(),
lv: 1,
exp: 0,
next_exp: 10,
hp: 20,
hp_max: 20,
attack: 0,
defense: 0,
gold: 42,
weapon: ItemId("stick".to_string()),
armor: ItemId("bandage".to_string()),
inventory: vec![
ItemId("monster_candy".to_string()),
ItemId("monster_candy".to_string()),
ItemId("monster_candy".to_string()),
ItemId("monster_candy".to_string()),
ItemId("monster_candy".to_string()),
ItemId("UNDEFITEM".to_string()),
],
inventory_capacity: 8,
}
}
}