Add enchantments and change data path resolution

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/1/head
trivernis 4 years ago
parent e7a73bb033
commit c2a7fd2ff1
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

1
.gitignore vendored

@ -1,2 +1,3 @@
/target /target
Cargo.lock Cargo.lock
.idea

@ -1,6 +1,6 @@
[package] [package]
name = "minecraft-data-rs" name = "minecraft-data-rs"
version = "0.1.0" version = "0.2.0"
authors = ["trivernis <trivernis@protonmail.com>"] authors = ["trivernis <trivernis@protonmail.com>"]
edition = "2018" edition = "2018"
readme = "README.md" readme = "README.md"
@ -16,3 +16,5 @@ serde_json = "1.0.64"
serde_derive = "1.0.125" serde_derive = "1.0.125"
serde = "1.0.125" serde = "1.0.125"
include_dir = "0.6.0" include_dir = "0.6.0"
itertools = "0.10.0"
lazy_static = "1.4.0"

@ -0,0 +1,53 @@
use crate::data::{get_version_specific_file, ENCHANTMENTS_FILE};
use crate::models::enchantment::Enchantment;
use crate::models::version::Version;
use crate::{DataError, DataResult};
use itertools::*;
use std::collections::HashMap;
use std::iter::FromIterator;
use std::sync::Arc;
#[derive(Clone, Debug)]
pub struct Enchantments {
version: Arc<Version>,
}
impl Enchantments {
pub fn new(version: Arc<Version>) -> Self {
Self { version }
}
/// Returns a list of enchantments
pub fn enchantments_array(&self) -> DataResult<Vec<Enchantment>> {
let content = get_version_specific_file(&self.version, ENCHANTMENTS_FILE)?;
serde_json::from_str::<Vec<Enchantment>>(&*content).map_err(DataError::from)
}
/// Returns a map of enchantments indexed by ID
pub fn enchantments(&self) -> DataResult<HashMap<u32, Enchantment>> {
Ok(HashMap::from_iter(
self.enchantments_array()?.into_iter().map(|e| (e.id, e)),
))
}
/// Returns a map of enchantments indexed by Name
pub fn enchantments_by_name(&self) -> DataResult<HashMap<String, Enchantment>> {
Ok(HashMap::from_iter(
self.enchantments_array()?
.into_iter()
.map(|e| (e.name.clone(), e)),
))
}
/// Returns enchantments grouped by category
pub fn enchantments_by_category(&self) -> DataResult<HashMap<String, Vec<Enchantment>>> {
Ok(HashMap::from_iter(
self.enchantments_array()?
.into_iter()
.group_by(|e| e.category.clone())
.into_iter()
.map(|(key, group)| (key, group.collect())),
))
}
}

@ -1,3 +1,4 @@
use crate::api::enchantments::Enchantments;
use crate::api::items::Items; use crate::api::items::Items;
use crate::api::recipes::Recipes; use crate::api::recipes::Recipes;
use crate::models::version::Version; use crate::models::version::Version;
@ -6,6 +7,7 @@ use std::sync::Arc;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
pub mod enchantments;
pub mod items; pub mod items;
mod recipes; mod recipes;
pub mod versions; pub mod versions;
@ -14,6 +16,7 @@ pub struct Api {
pub version: Arc<Version>, pub version: Arc<Version>,
pub items: Items, pub items: Items,
pub recipes: Recipes, pub recipes: Recipes,
pub enchantments: Enchantments,
} }
impl Api { impl Api {
@ -23,6 +26,7 @@ impl Api {
version: Arc::clone(&version), version: Arc::clone(&version),
items: Items::new(Arc::clone(&version)), items: Items::new(Arc::clone(&version)),
recipes: Recipes::new(Arc::clone(&version)), recipes: Recipes::new(Arc::clone(&version)),
enchantments: Enchantments::new(Arc::clone(&version)),
} }
} }
} }

@ -0,0 +1,47 @@
use crate::api::tests::{get_api, get_test_versions};
#[test]
pub fn test_enchantments_array() {
let versions = get_test_versions();
for version in versions {
let api = get_api(version);
let enchantments_array = api.enchantments.enchantments_array().unwrap();
assert_ne!(enchantments_array.len(), 0);
}
}
#[test]
pub fn test_enchantments() {
let versions = get_test_versions();
for version in versions {
let api = get_api(version);
let enchantments = api.enchantments.enchantments().unwrap();
assert_ne!(enchantments.len(), 0);
}
}
#[test]
pub fn test_enchantments_by_name() {
let versions = get_test_versions();
for version in versions {
let api = get_api(version);
let by_name = api.enchantments.enchantments_by_name().unwrap();
assert!(by_name.get("unbreaking").is_some());
assert!(by_name.get("protection").is_some());
}
}
#[test]
pub fn test_enchantments_by_category() {
let versions = get_test_versions();
for version in versions {
let api = get_api(version);
let by_category = api.enchantments.enchantments_by_category().unwrap();
assert!(by_category.get("breakable").is_some());
assert_ne!(by_category.get("breakable").unwrap().len(), 0);
}
}

@ -2,6 +2,7 @@ use crate::api::versions::{available_versions, versions};
use crate::api::Api; use crate::api::Api;
use crate::models::version::Version; use crate::models::version::Version;
mod enchantments;
mod items; mod items;
mod recipes; mod recipes;
mod versions; mod versions;

@ -0,0 +1,9 @@
use serde_json::Value;
use std::collections::HashMap;
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all(deserialize = "camelCase", serialize = "snake_case"))]
pub(crate) struct Datapaths {
pub pc: HashMap<String, HashMap<String, String>>,
pub pe: HashMap<String, HashMap<String, String>>,
}

@ -1,31 +1,36 @@
mod datapaths;
use crate::data::datapaths::Datapaths;
use crate::models::version::Version; use crate::models::version::Version;
use crate::{DataError, DataResult}; use crate::{DataError, DataResult};
use include_dir::Dir; use include_dir::Dir;
use std::collections::HashMap;
pub static MINECRAFT_DATA: Dir = include_dir::include_dir!("minecraft-data/data/pc"); pub static MINECRAFT_DATA: Dir = include_dir::include_dir!("minecraft-data/data");
pub static BIOMES_FILE: &str = "biomes.json"; pub static BIOMES_FILE: &str = "biomes";
pub static BLOCK_LOOT_FILE: &str = "blockLoot.json"; pub static BLOCK_LOOT_FILE: &str = "blockLoot";
pub static BLOCKS_FILE: &str = "blocks.json"; pub static BLOCKS_FILE: &str = "blocks";
pub static COMMANDS_FILE: &str = "commands.json"; pub static COMMANDS_FILE: &str = "commands";
pub static ENTITIES_FILE: &str = "entities.json"; pub static ENTITIES_FILE: &str = "entities";
pub static ENTITY_LOOT_FILE: &str = "entityLoot.json"; pub static ENTITY_LOOT_FILE: &str = "entityLoot";
pub static ITEMS_FILE: &str = "items.json"; pub static ITEMS_FILE: &str = "items";
pub static LOGIN_PACKET_FILE: &str = "loginPacket.json"; pub static LOGIN_PACKET_FILE: &str = "loginPacket";
pub static MATERIALS_FILE: &str = "materials.json"; pub static MATERIALS_FILE: &str = "materials";
pub static PROTOCOL_FILE: &str = "protocol.json"; pub static PROTOCOL_FILE: &str = "protocol";
pub static RECIPES_FILE: &str = "recipes.json"; pub static RECIPES_FILE: &str = "recipes";
pub static TINTS_FILE: &str = "tints.json"; pub static TINTS_FILE: &str = "tints";
pub static ENCHANTMENTS_FILE: &str = "enchantments";
// pub static VERSION_FILE: &str = "version.json"; // pub static VERSION_FILE: &str = "version.json";
pub static MAP_ICONS_FILE: &str = "mapIcons.json"; pub static MAP_ICONS_FILE: &str = "mapIcons";
pub static PARTICLES_FILE: &str = "particles.json"; pub static PARTICLES_FILE: &str = "particles";
pub static PROTOCOL_VERSIONS_FILE: &str = "protocolVersions.json"; pub static PROTOCOL_VERSIONS_FILE: &str = "protocolVersions";
pub static VERSIONS_FILE: &str = "versions.json"; pub static VERSIONS_FILE: &str = "versions";
/// Returns the string encoded content of the common file /// Returns the string encoded content of the common file
pub fn get_common_file(filename: &str) -> DataResult<String> { pub fn get_common_file(filename: &str) -> DataResult<String> {
MINECRAFT_DATA MINECRAFT_DATA
.get_file(format!("common/{}", filename)) .get_file(format!("pc/common/{}.json", filename))
.ok_or(DataError::NotFoundError(filename.to_string()))? .ok_or(DataError::NotFoundError(filename.to_string()))?
.contents_utf8() .contents_utf8()
.ok_or(DataError::InvalidEncodingError(filename.to_string())) .ok_or(DataError::InvalidEncodingError(filename.to_string()))
@ -34,23 +39,10 @@ pub fn get_common_file(filename: &str) -> DataResult<String> {
/// Returns the string encoded content of the version specific file /// Returns the string encoded content of the version specific file
pub fn get_version_specific_file(version: &Version, filename: &str) -> DataResult<String> { pub fn get_version_specific_file(version: &Version, filename: &str) -> DataResult<String> {
let search_folders = vec![ let path = get_path(version, filename)?;
version.minecraft_version.clone(), MINECRAFT_DATA
version.major_version.clone(), .get_file(format!("{}/{}.json", path, filename))
version.major_first(), .ok_or(DataError::NotFoundError(format!(
version.previous_major(),
version.previous_major_first(),
];
let mut data = None;
for folder in search_folders {
data = MINECRAFT_DATA.get_file(format!("{}/{}", folder, filename));
if data.is_some() {
break;
}
}
data.ok_or(DataError::NotFoundError(format!(
"{}/{}", "{}/{}",
version.minecraft_version, filename version.minecraft_version, filename
)))? )))?
@ -58,3 +50,29 @@ pub fn get_version_specific_file(version: &Version, filename: &str) -> DataResul
.ok_or(DataError::InvalidEncodingError(filename.to_string())) .ok_or(DataError::InvalidEncodingError(filename.to_string()))
.map(|d| d.to_string()) .map(|d| d.to_string())
} }
/// Returns the data path for a given file
pub fn get_path(version: &Version, filename: &str) -> DataResult<String> {
lazy_static::lazy_static! {
static ref PATHS: Datapaths = getDatapaths().unwrap();
};
PATHS
.pc
.get(&version.minecraft_version)
.ok_or(DataError::NotFoundError(version.minecraft_version.clone()))?
.get(filename)
.cloned()
.ok_or(DataError::NotFoundError(filename.to_string()))
}
/// Returns the parsed data paths
fn getDatapaths() -> DataResult<Datapaths> {
let content = MINECRAFT_DATA
.get_file("dataPaths.json")
.ok_or(DataError::NotFoundError("dataPaths.json".to_string()))?
.contents_utf8()
.ok_or(DataError::InvalidEncodingError(
"dataPaths.json".to_string(),
))?;
serde_json::from_str::<Datapaths>(content).map_err(DataError::from)
}

@ -0,0 +1,23 @@
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all(deserialize = "camelCase", serialize = "snake_case"))]
pub struct Enchantment {
pub id: u32,
pub name: String,
pub display_name: String,
pub max_level: u8,
pub min_cost: Cost,
pub max_cost: Cost,
pub treasure_only: bool,
pub exclude: Vec<String>,
pub category: String,
pub weight: u8,
pub tradeable: bool,
pub discoverable: bool,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all(deserialize = "camelCase", serialize = "snake_case"))]
pub struct Cost {
pub a: i32,
pub b: i32,
}

@ -1,5 +1,3 @@
use serde_json::Value;
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
#[serde(rename_all(deserialize = "camelCase", serialize = "snake_case"))] #[serde(rename_all(deserialize = "camelCase", serialize = "snake_case"))]
pub struct Item { pub struct Item {
@ -10,6 +8,13 @@ pub struct Item {
pub fixed_with: Option<Vec<String>>, pub fixed_with: Option<Vec<String>>,
pub max_durability: Option<u32>, pub max_durability: Option<u32>,
pub name: String, pub name: String,
pub variations: Option<Value>, pub variations: Option<Vec<Variation>>,
pub durability: Option<u32>, pub durability: Option<u32>,
} }
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all(deserialize = "camelCase", serialize = "snake_case"))]
pub struct Variation {
pub metadata: u32,
pub display_name: String,
}

@ -1,3 +1,4 @@
pub mod enchantment;
pub mod item; pub mod item;
pub mod recipe; pub mod recipe;
pub mod version; pub mod version;

Loading…
Cancel
Save