You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Nothing/src-tauri/poe_data/src/world_area.rs

252 lines
6.7 KiB

use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::ops::Deref;
use fuzzy_matcher::skim::SkimMatcherV2;
use fuzzy_matcher::FuzzyMatcher;
use serde_derive::Deserialize;
use serde_derive::Serialize;
#[allow(dead_code)]
type UnprocessedAreas = Vec<UnprocessedArea>;
type StepOneUnprocessedAreas = HashMap<String, UnprocessedArea>;
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct UnprocessedArea {
#[serde(rename = "name")]
pub name: String,
#[serde(rename = "id")]
pub named_id: String,
#[serde(rename = "area_level")]
pub area_level: i64,
#[serde(rename = "act")]
pub act: i64,
#[serde(rename = "is_town")]
pub is_town: bool,
#[serde(rename = "has_waypoint")]
pub has_waypoint: bool,
#[serde(rename = "connections")]
pub connections_world_areas_keys: Vec<String>,
}
pub type AreaName = String;
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct WorldArea {
pub name: String,
pub named_id: String,
pub area_level: i64,
pub act: i64,
pub is_town: bool,
pub has_waypoint: bool,
pub connections_world_areas_keys: Vec<String>,
}
pub type AreaId = usize;
pub type WorldAreasMap = HashMap<String, WorldArea>;
#[allow(dead_code)]
pub fn load_world_areas_map(content: &'static str) -> WorldAreasMap {
serde_json::from_str::<WorldAreasMap>(content).expect("Could not load world areas json")
}
#[macro_export]
macro_rules! load_world_areas {
($e:expr) => {
crate::world_area::load_world_areas_map(&include_str!($e))
};
}
#[allow(dead_code)]
pub struct WorldAreas {
pub areas_map: WorldAreasMap,
matcher: Matcher,
}
impl WorldAreas {
#[allow(dead_code)]
pub fn new(areas: WorldAreasMap, matcher: Matcher) -> Self {
Self {
areas_map: areas,
matcher,
}
}
#[allow(dead_code)]
pub fn fuzzy_area(&self, count: usize, area: &str) -> Vec<WorldArea> {
let mut matches = Vec::new();
for (_key_id, v) in &self.areas_map {
if let Some(mut score) = self.matcher.fuzzy_match(&v.name, area) {
if v.name.contains(area) {
score = i64::MAX;
}
let f_entry = FEntry {
area: v.clone(),
score,
};
matches.push(f_entry);
}
}
matches.sort_by(|entry1, entry2| {
entry1
.score
.cmp(&entry2.score)
.reverse()
.then(entry1.area.area_level.cmp(&entry2.area.area_level))
});
let matches_areas = matches
.into_iter()
.map(|entry| entry.area)
.take(count)
.collect::<Vec<WorldArea>>();
matches_areas
}
#[allow(dead_code)]
pub fn by_area_id(&self, key: String) -> Option<&WorldArea> {
self.areas_map.get(&key)
}
}
#[derive(PartialEq, Eq, Clone, Debug)]
struct FEntry {
area: WorldArea,
score: i64,
}
impl Ord for FEntry {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other).unwrap()
}
}
impl PartialOrd for FEntry {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.score.cmp(&other.score))
}
}
pub struct Matcher(SkimMatcherV2);
impl Matcher {
#[allow(dead_code)]
pub fn new() -> Self {
let matcher = SkimMatcherV2::default().ignore_case().use_cache(true);
Matcher(matcher)
}
}
impl Deref for Matcher {
type Target = SkimMatcherV2;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Matcher {
#[allow(dead_code)]
pub fn fuzzy_area(&self, areas: &WorldAreasMap, area: &str) -> Vec<WorldArea> {
let mut matches: BinaryHeap<FEntry> = BinaryHeap::new();
for (_key_id, v) in areas {
if let Some(score) = self.fuzzy_match(&v.name, area) {
let f_entry = FEntry {
area: v.clone(),
score,
};
matches.push(f_entry);
}
}
let mut values = matches.into_iter();
let mut return_vec = Vec::new();
for _i in 0..30 {
if let Some(value) = values.next() {
return_vec.push(value.area.clone());
} else {
break;
}
}
return_vec
}
}
#[allow(dead_code)]
pub fn repack(content: &str, out_path: &str) {
let areas_json = serde_json::from_str::<StepOneUnprocessedAreas>(content).unwrap().into_iter().map(|(k,v)| v).collect::<Vec<UnprocessedArea>>();
let area_map = areas_json
.into_iter()
.filter_map(|w_a| {
if w_a.act < 11
&& !w_a.connections_world_areas_keys.is_empty()
&& !w_a.named_id.starts_with("Map")
&& !w_a.named_id.starts_with("Descent")
&& !w_a.named_id.starts_with("EndlessLedge")
{
Some((
w_a.named_id.clone(),
WorldArea {
name: w_a.name,
named_id: w_a.named_id,
area_level: w_a.area_level,
act: w_a.act,
is_town: w_a.is_town,
has_waypoint: w_a.has_waypoint,
connections_world_areas_keys: w_a.connections_world_areas_keys,
},
))
} else {
None
}
})
.collect::<WorldAreasMap>();
let new_json = serde_json::to_string(&area_map).unwrap();
std::fs::write(out_path, &new_json).expect("Could not write to file");
}
#[allow(dead_code)]
pub fn repack_full(content: &str, out_path: &str) {
let areas_json = serde_json::from_str::<StepOneUnprocessedAreas>(content).unwrap().into_iter().map(|(k,v)| v).collect::<Vec<UnprocessedArea>>();
let area_map = areas_json
.into_iter()
.map(|w_a| {
(
w_a.named_id.clone(),
WorldArea {
name: w_a.name,
named_id: w_a.named_id,
area_level: w_a.area_level,
act: w_a.act,
is_town: w_a.is_town,
has_waypoint: w_a.has_waypoint,
connections_world_areas_keys: w_a.connections_world_areas_keys,
},
)
})
.collect::<WorldAreasMap>();
let new_json = serde_json::to_string(&area_map).unwrap();
std::fs::write(out_path, &new_json).expect("Could not write to file");
}