diff --git a/game_data/src/lib.rs b/game_data/src/lib.rs index 758187f..0cb7e84 100644 --- a/game_data/src/lib.rs +++ b/game_data/src/lib.rs @@ -7,9 +7,15 @@ pub use config::*; mod locales; pub use locales::*; +mod search; +pub use search::*; + use serde::{Deserialize, Serialize}; use simulator::{Action, ActionMask, Settings}; +pub const HQ_ICON_CHAR: char = '\u{e03c}'; +pub const CL_ICON_CHAR: char = '\u{e03d}'; + #[derive(Debug, Clone, Copy)] pub struct Item { pub item_level: u16, diff --git a/game_data/src/search.rs b/game_data/src/search.rs new file mode 100644 index 0000000..cfafab8 --- /dev/null +++ b/game_data/src/search.rs @@ -0,0 +1,62 @@ +use crate::{ + get_item_name, Consumable, Locale, CL_ICON_CHAR, HQ_ICON_CHAR, MEALS, POTIONS, RECIPES, +}; + +fn contains_noncontiguous(string: &str, pattern: &str) -> bool { + let mut it = string.split_whitespace(); + for c in pattern.split_whitespace() { + loop { + let Some(c2) = it.next() else { + return false; + }; + if c2.contains(c) { + break; + } + } + } + true +} + +fn preprocess_pattern(pattern: &str) -> String { + pattern + .to_lowercase() + .replace([HQ_ICON_CHAR, CL_ICON_CHAR], "") +} + +pub fn find_recipes(search_string: &str, locale: Locale) -> Vec { + let pattern = preprocess_pattern(search_string); + RECIPES + .iter() + .enumerate() + .filter_map(|(index, recipe)| { + let item_name = get_item_name(recipe.item_id, false, locale); + match contains_noncontiguous(&item_name.to_lowercase(), &pattern) { + true => Some(index), + false => None, + } + }) + .collect() +} + +fn find_consumables(search_string: &str, locale: Locale, consumables: &[Consumable]) -> Vec { + let pattern = preprocess_pattern(search_string); + consumables + .iter() + .enumerate() + .filter_map(|(index, consumable)| { + let item_name = get_item_name(consumable.item_id, false, locale); + match contains_noncontiguous(&item_name.to_lowercase(), &pattern) { + true => Some(index), + false => None, + } + }) + .collect() +} + +pub fn find_meals(search_string: &str, locale: Locale) -> Vec { + find_consumables(search_string, locale, MEALS) +} + +pub fn find_potions(search_string: &str, locale: Locale) -> Vec { + find_consumables(search_string, locale, POTIONS) +} diff --git a/src/lib.rs b/src/lib.rs index 23c9003..4e8dee9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,5 @@ pub use app::MacroSolverApp; pub use worker::Worker; mod config; -mod utils; mod widgets; mod worker; diff --git a/src/utils.rs b/src/utils.rs deleted file mode 100644 index 4bddd31..0000000 --- a/src/utils.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn contains_noncontiguous(string: &str, pattern: &str) -> bool { - let mut it = string.split_whitespace(); - for c in pattern.split_whitespace() { - loop { - let Some(c2) = it.next() else { - return false; - }; - if c2.contains(c) { - break; - } - } - } - true -} diff --git a/src/widgets/food_select.rs b/src/widgets/food_select.rs index 319aa06..d75cae4 100644 --- a/src/widgets/food_select.rs +++ b/src/widgets/food_select.rs @@ -3,26 +3,14 @@ use egui::{ Align, Id, Layout, Widget, }; use egui_extras::Column; -use game_data::{get_item_name, Consumable, CrafterStats, Locale}; - -use crate::utils::contains_noncontiguous; +use game_data::{find_meals, get_item_name, Consumable, CrafterStats, Locale}; #[derive(Default)] struct FoodFinder {} impl ComputerMut<(&str, Locale), Vec> for FoodFinder { fn compute(&mut self, (text, locale): (&str, Locale)) -> Vec { - game_data::MEALS - .iter() - .enumerate() - .filter_map(|(index, item)| { - let item_name = get_item_name(item.item_id, item.hq, locale); - match contains_noncontiguous(&item_name.to_lowercase(), text) { - true => Some(index), - false => None, - } - }) - .collect() + find_meals(text, locale) } } @@ -84,7 +72,7 @@ impl<'a> Widget for FoodSelect<'a> { ui.horizontal(|ui| { ui.label("Search:"); if ui.text_edit_singleline(&mut search_text).changed() { - search_text = search_text.replace("\0", "").replace("(HQ)", "\u{e03c}"); + search_text = search_text.replace("\0", ""); } }); ui.separator(); @@ -92,7 +80,7 @@ impl<'a> Widget for FoodSelect<'a> { let mut search_result = Vec::new(); ui.ctx().memory_mut(|mem| { let search_cache = mem.caches.cache::>(); - search_result = search_cache.get((&search_text.to_lowercase(), self.locale)); + search_result = search_cache.get((&search_text, self.locale)); }); ui.ctx().data_mut(|data| { diff --git a/src/widgets/potion_select.rs b/src/widgets/potion_select.rs index 4bb28d2..1dbf695 100644 --- a/src/widgets/potion_select.rs +++ b/src/widgets/potion_select.rs @@ -3,26 +3,14 @@ use egui::{ Align, Id, Layout, Widget, }; use egui_extras::Column; -use game_data::{get_item_name, Consumable, CrafterStats, Locale}; - -use crate::utils::contains_noncontiguous; +use game_data::{find_potions, get_item_name, Consumable, CrafterStats, Locale}; #[derive(Default)] struct PotionFinder {} impl ComputerMut<(&str, Locale), Vec> for PotionFinder { fn compute(&mut self, (text, locale): (&str, Locale)) -> Vec { - game_data::POTIONS - .iter() - .enumerate() - .filter_map(|(index, item)| { - let item_name = get_item_name(item.item_id, item.hq, locale); - match contains_noncontiguous(&item_name.to_lowercase(), text) { - true => Some(index), - false => None, - } - }) - .collect() + find_potions(text, locale) } } @@ -84,7 +72,7 @@ impl<'a> Widget for PotionSelect<'a> { ui.horizontal(|ui| { ui.label("Search:"); if ui.text_edit_singleline(&mut search_text).changed() { - search_text = search_text.replace("\0", "").replace("(HQ)", "\u{e03c}"); + search_text = search_text.replace("\0", ""); } }); ui.separator(); @@ -92,7 +80,7 @@ impl<'a> Widget for PotionSelect<'a> { let mut search_result = Vec::new(); ui.ctx().memory_mut(|mem| { let search_cache = mem.caches.cache::>(); - search_result = search_cache.get((&search_text.to_lowercase(), self.locale)); + search_result = search_cache.get((&search_text, self.locale)); }); ui.ctx().data_mut(|data| { diff --git a/src/widgets/recipe_select.rs b/src/widgets/recipe_select.rs index 686d4cf..ffcd71c 100644 --- a/src/widgets/recipe_select.rs +++ b/src/widgets/recipe_select.rs @@ -4,30 +4,18 @@ use egui::{ }; use egui_extras::Column; use game_data::{ - get_game_settings, get_item_name, get_job_name, Consumable, Ingredient, Locale, RLVLS, + find_recipes, get_game_settings, get_item_name, get_job_name, Consumable, Ingredient, Locale, + RLVLS, }; -use crate::{ - config::{CrafterConfig, QualitySource, RecipeConfiguration}, - utils::contains_noncontiguous, -}; +use crate::config::{CrafterConfig, QualitySource, RecipeConfiguration}; #[derive(Default)] struct RecipeFinder {} impl ComputerMut<(&str, Locale), Vec> for RecipeFinder { fn compute(&mut self, (text, locale): (&str, Locale)) -> Vec { - game_data::RECIPES - .iter() - .enumerate() - .filter_map(|(index, recipe)| { - let item_name = get_item_name(recipe.item_id, false, locale); - match contains_noncontiguous(&item_name.to_lowercase(), text) { - true => Some(index), - false => None, - } - }) - .collect() + find_recipes(text, locale) } } @@ -69,7 +57,7 @@ impl<'a> RecipeSelect<'a> { ui.horizontal(|ui| { ui.label("Search:"); if ui.text_edit_singleline(&mut search_text).changed() { - search_text = search_text.replace("\0", "").replace("(CL)", "\u{e03d}"); + search_text = search_text.replace("\0", ""); } }); ui.separator(); @@ -77,8 +65,7 @@ impl<'a> RecipeSelect<'a> { let mut search_result = Vec::new(); ui.ctx().memory_mut(|mem| { let search_cache = mem.caches.cache::>(); - let cache_search_string = search_text.trim_end_matches('\u{e03c}').to_lowercase(); - search_result = search_cache.get((&cache_search_string, self.locale)); + search_result = search_cache.get((&search_text, self.locale)); }); ui.ctx().data_mut(|data| {