use crate::data_source;
use crate::error::{Edition, McDataError};
use crate::loader::load_data_from_path;
use crate::structs::DataPaths;
use once_cell::sync::OnceCell;
use std::path::PathBuf;
use std::sync::Arc;
static LOADED_DATA_PATHS: OnceCell<Result<Arc<DataPaths>, McDataError>> = OnceCell::new();
fn get_data_paths() -> Result<Arc<DataPaths>, McDataError> {
let stored_result_ref = LOADED_DATA_PATHS.get_or_try_init(|| {
log::debug!("Attempting to load dataPaths.json for the first time...");
let data_root = data_source::get_data_root()?;
let path = data_root.join("dataPaths.json");
Ok(load_data_from_path::<DataPaths>(&path).map(Arc::new)) });
match stored_result_ref {
Ok(Ok(arc_data_ref)) => Ok(arc_data_ref.clone()),
Ok(Err(inner_error_ref)) => {
Err(McDataError::CachedError(format!(
"Previously failed to load dataPaths.json: {}",
inner_error_ref
)))
}
Err(init_error) => {
Err(init_error)
}
}
}
fn get_path_suffix(edition: Edition, version: &str, data_key: &str) -> Result<String, McDataError> {
let data_paths = get_data_paths()?;
let edition_paths = match edition {
Edition::Pc => &data_paths.pc,
Edition::Bedrock => &data_paths.bedrock,
};
edition_paths
.get(version) .and_then(|version_paths| version_paths.get(data_key)) .cloned() .ok_or_else(|| McDataError::DataPathNotFound {
mc_version: version.to_string(),
edition,
data_key: data_key.to_string(),
})
}
pub fn get_full_data_path(
edition: Edition,
version: &str,
data_key: &str,
) -> Result<PathBuf, McDataError> {
let suffix = get_path_suffix(edition, version, data_key)?; let base_path = data_source::get_data_root()?;
let relative_path = PathBuf::from(suffix);
let dir_path = base_path.join(&relative_path);
let file_stem = data_key;
log::trace!(
"Searching for file stem '{}' in directory {}",
file_stem,
dir_path.display()
);
match std::fs::read_dir(&dir_path) {
Ok(entries) => {
for entry_result in entries {
if let Ok(entry) = entry_result {
let path = entry.path();
if path.is_file() {
if let Some(stem) = path.file_stem().and_then(|s| s.to_str()) {
if stem == file_stem {
log::trace!("Found data file: {}", path.display());
return Ok(path);
}
}
}
} else {
log::warn!(
"Error reading directory entry in {}: {:?}",
dir_path.display(),
entry_result.err()
);
}
}
log::warn!(
"Data file with stem '{}' not found in directory {}",
file_stem,
dir_path.display()
);
Err(McDataError::DataFileNotFound {
data_key: data_key.to_string(),
path: dir_path.join(format!("{}.*", file_stem)), })
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
log::warn!("Data directory not found: {}", dir_path.display());
Err(McDataError::DataFileNotFound {
data_key: data_key.to_string(),
path: dir_path, })
}
Err(e) => {
log::error!("I/O error reading directory {}: {}", dir_path.display(), e);
Err(McDataError::IoError {
path: dir_path,
source: e,
})
}
}
}