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.
237 lines
5.9 KiB
237 lines
5.9 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>;
|
|
|
|
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
struct UnprocessedArea {
|
|
#[serde(rename = "Id")]
|
|
pub named_id: String,
|
|
|
|
#[serde(rename = "_rid")]
|
|
pub key_id: usize,
|
|
|
|
#[serde(rename = "Name")]
|
|
pub name: String,
|
|
|
|
#[serde(rename = "Act")]
|
|
pub act: i64,
|
|
|
|
#[serde(rename = "IsTown")]
|
|
pub is_town: bool,
|
|
|
|
#[serde(rename = "HasWaypoint")]
|
|
pub has_waypoint: bool,
|
|
|
|
#[serde(rename = "Connections_WorldAreasKeys")]
|
|
pub connections_world_areas_keys: Vec<i64>,
|
|
|
|
#[serde(rename = "IsVaalArea")]
|
|
pub is_vaal_area: bool,
|
|
|
|
#[serde(rename = "Unknown64")]
|
|
pub unknown64: bool,
|
|
|
|
#[serde(rename = "Unknown9")]
|
|
pub unknown9: i64,
|
|
}
|
|
|
|
pub type AreaName = String;
|
|
|
|
#[derive(Default, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
|
pub struct WorldArea {
|
|
pub name: String,
|
|
pub named_id: String,
|
|
pub act: i64,
|
|
pub key_id: usize,
|
|
pub is_town: bool,
|
|
pub has_waypoint: bool,
|
|
pub connections_world_areas_keys: Vec<i64>,
|
|
}
|
|
|
|
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.key_id.cmp(&entry2.area.key_id))
|
|
});
|
|
|
|
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::<UnprocessedAreas>(content);
|
|
|
|
let area_map = areas_json
|
|
.expect("Could not read world areas")
|
|
.into_iter()
|
|
.filter_map(|w_a| {
|
|
if w_a.act < 11
|
|
&& !w_a.is_vaal_area
|
|
&& !w_a.connections_world_areas_keys.is_empty()
|
|
&& !w_a.unknown64
|
|
&& !w_a.named_id.starts_with("Map")
|
|
&& !w_a.named_id.starts_with("Descent")
|
|
&& !w_a.named_id.starts_with("EndlessLedge")
|
|
&& w_a.unknown9 != 20
|
|
{
|
|
Some((
|
|
w_a.named_id.clone(),
|
|
WorldArea {
|
|
name: w_a.name,
|
|
named_id: w_a.named_id,
|
|
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,
|
|
key_id: w_a.key_id,
|
|
},
|
|
))
|
|
} 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");
|
|
}
|