@@ 1,3 1,5 @@
+use std::collections::HashMap;
+
use bevy::{input_focus::{AutoFocus, InputFocus}, ui::RelativeCursorPosition};
use crate::{attachment::PartInShip, client::colors, config::recipe::RecipesConfig, ecs::{CanCraft, CraftingUi, Drill, MainCamera, Me, Part, SingleStorage, ToggleDrillEvent}, prelude::*};
@@ 6,25 8,29 @@ pub fn crafting_ui_plugin(app: &mut App) {
app.init_resource::<RecipeCollection>();
app.add_systems(Startup, load_recipes);
app.add_systems(PreUpdate, (initial_create_recipe_list, update_recipe_list));
- app.add_systems(Update, (close_button, drill_button, drill_state_change, single_storage_display));
+ app.add_systems(Update, (close_button, drill_button, drill_state_change,
+ single_storage_display, recipe_buttons));
}
#[derive(Component)]
struct CloseButton(Entity); // stores corresponding menu entity
-#[derive(Component)]
+#[derive(Component, Clone)]
struct PreviousInteraction(Interaction);
#[derive(Component)]
struct DrillButton(Entity); // stores corresponding part
#[derive(Component)]
struct SingleStorageDisplay(Entity); // stores corresponding part
#[derive(Component)]
-struct RecipesHolder;
+struct RecipesHolder(Entity); // stores corresponding part
#[derive(Component)]
-struct PendingRecipesHolder;
+struct PendingRecipesHolder(Entity); // stores corresponding part
#[derive(Resource, Default)]
struct RecipeCollection {
handle: Option<Handle<RecipesConfig>>,
}
+// TODO: use recipe inputs for client-side validation?
+#[derive(Component, Clone)]
+struct RecipeElement(Entity, String, HashMap<String, u32>); // stores corresponding part and recipe's part name and inputs
fn load_recipes(asset_server: Res<AssetServer>, mut recipe_collection: ResMut<RecipeCollection>) {
recipe_collection.handle = Some(asset_server.load("config/recipes.rc.toml"));
@@ 147,23 153,23 @@ fn setup_ui(
flex_direction: FlexDirection::Column,
..Default::default()
},
- PendingRecipesHolder,
+ PendingRecipesHolder(parent_part),
));
});
}
fn initial_create_recipe_list(
mut commands: Commands,
- added_recipes_holders: Query<Entity, With<PendingRecipesHolder>>,
+ added_recipes_holders: Query<(Entity, &PendingRecipesHolder)>,
recipe_collection: ResMut<RecipeCollection>,
recipes_config: Res<Assets<RecipesConfig>>,
) {
if let Some(strong_recipes_config) = recipes_config.get(&recipe_collection.handle.clone().unwrap()) {
- for recipe_holder in &added_recipes_holders {
+ for (recipe_holder, pending_recipes_holder) in &added_recipes_holders {
let mut recipe_holder = commands.get_entity(recipe_holder).unwrap();
- create_recipe_list(&mut recipe_holder, strong_recipes_config);
+ create_recipe_list(pending_recipes_holder.0, &mut recipe_holder, strong_recipes_config);
recipe_holder
- .insert(RecipesHolder)
+ .insert(RecipesHolder(pending_recipes_holder.0))
.remove::<PendingRecipesHolder>();
}
}
@@ 173,7 179,7 @@ fn update_recipe_list(
recipe_collection: ResMut<RecipeCollection>,
assets: ResMut<Assets<RecipesConfig>>,
mut commands: Commands,
- recipes_holders: Query<Entity, With<RecipesHolder>>,
+ recipes_holders: Query<(Entity, &RecipesHolder)>,
) {
let Some(handle) = recipe_collection.handle.as_ref() else {
return
@@ 184,16 190,17 @@ fn update_recipe_list(
if *id == handle.id() {
debug!("recipe list config modified - reloading lists");
let strong_recipes_config = assets.get(*id).unwrap();
- for recipe_holder in &recipes_holders {
- let mut recipe_holder = commands.get_entity(recipe_holder).unwrap();
+ for (recipe_holder_entity, recipes_holder) in &recipes_holders {
+ let mut recipe_holder = commands.get_entity(recipe_holder_entity).unwrap();
recipe_holder.despawn_children();
- create_recipe_list(&mut recipe_holder, strong_recipes_config);
+ create_recipe_list(recipes_holder.0, &mut recipe_holder, strong_recipes_config);
}
}
}
}
}
fn create_recipe_list(
+ parent_entity: Entity,
recipe_holder: &mut EntityCommands,
strong_recipes_config: &RecipesConfig,
) {
@@ 206,25 213,56 @@ fn create_recipe_list(
ui_recipes.push((
recipe.order,
(Node {
+ width: Val::Auto,
+ ..Default::default()
+ },
+ RecipeElement(parent_entity, module_name.clone(), recipe.inputs.clone()),
+ BackgroundColor(colors::MANTLE),
+ PreviousInteraction(Interaction::None),
+ Button),
+ (Node {
..Default::default()
},
TextFont {
font_size: 10.0,
..Default::default()
},
- Text::new(format!("{}: {}", module_name, resource_list)))
+ Text::new(format!("{}: {}", module_name, resource_list))),
));
}
}
// ordering stuff
ui_recipes.sort_by(|a, b| a.0.cmp(&b.0));
- let ui_recipes = ui_recipes.iter().map(|recipe| &recipe.1).collect::<Vec<_>>();
recipe_holder.with_children(move |parent| {
for recipe in ui_recipes {
- parent.spawn(recipe.clone());
+ parent.spawn(recipe.1.clone())
+ .with_child(recipe.2);
}
});
}
+fn recipe_buttons(
+ mut interaction_query: Query<(&Interaction, &mut PreviousInteraction, &mut BackgroundColor, &RecipeElement),
+ Changed<Interaction>>,
+) {
+ for (interaction, mut previous_interaction, mut color, recipe) in &mut interaction_query {
+ match *interaction {
+ Interaction::Pressed => {
+ *color = colors::SURFACE_1.into();
+ }
+ Interaction::Hovered => {
+ *color = colors::SURFACE_0.into();
+ if previous_interaction.0 == Interaction::Pressed {
+ // released
+ debug!("{:?} {} {:?}", recipe.0, recipe.1, recipe.2);
+ }
+ }
+ Interaction::None => {
+ *color = colors::MANTLE.into();
+ }
+ }
+ previous_interaction.0 = *interaction;
+ }
+}
fn drill_button(
mut interaction_query: Query<