Add versions and items api
Signed-off-by: trivernis <trivernis@protonmail.com>pull/1/head
commit
e03e8adf1f
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
Cargo.lock
|
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "minecraft-data"]
|
||||||
|
path = minecraft-data
|
||||||
|
url = git@github.com:PrismarineJS/minecraft-data.git
|
@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CsvFileAttributes">
|
||||||
|
<option name="attributeMap">
|
||||||
|
<map>
|
||||||
|
<entry key="/src/data/mod.rs">
|
||||||
|
<value>
|
||||||
|
<Attribute>
|
||||||
|
<option name="separator" value=":" />
|
||||||
|
</Attribute>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DiscordProjectSettings">
|
||||||
|
<option name="show" value="PROJECT_FILES" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="CPP_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/minecraft-data-rs.iml" filepath="$PROJECT_DIR$/.idea/minecraft-data-rs.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "minecraft-data-rs"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["trivernis <trivernis@protonmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
thiserror = "1.0.24"
|
||||||
|
serde_json = "1.0.64"
|
||||||
|
serde_derive = "1.0.125"
|
||||||
|
serde = "1.0.125"
|
||||||
|
include_dir = "0.6.0"
|
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 920d361e13351bbbd812c3bbd0ed05f4194b05fe
|
@ -0,0 +1,39 @@
|
|||||||
|
use crate::data::{get_version_specific_file, ITEMS_FILE};
|
||||||
|
use crate::models::item::Item;
|
||||||
|
use crate::models::version::Version;
|
||||||
|
use crate::{DataError, DataResult};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// API to access item information
|
||||||
|
pub struct Items {
|
||||||
|
version: Arc<Version>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Items {
|
||||||
|
pub fn new(version: Arc<Version>) -> Self {
|
||||||
|
Self { version }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the items
|
||||||
|
pub fn items_array(&self) -> DataResult<Vec<Item>> {
|
||||||
|
let content = get_version_specific_file(&self.version, ITEMS_FILE)?;
|
||||||
|
|
||||||
|
serde_json::from_str::<Vec<Item>>(&*content).map_err(DataError::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the items indexed by name
|
||||||
|
pub fn items_by_name(&self) -> DataResult<HashMap<String, Item>> {
|
||||||
|
Ok(HashMap::from_iter(
|
||||||
|
self.items_array()?.into_iter().map(|i| (i.name.clone(), i)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the items indexed by ID
|
||||||
|
pub fn items(&self) -> DataResult<HashMap<u32, Item>> {
|
||||||
|
Ok(HashMap::from_iter(
|
||||||
|
self.items_array()?.into_iter().map(|i| (i.id.clone(), i)),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
use crate::api::items::Items;
|
||||||
|
use crate::models::version::Version;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
pub mod items;
|
||||||
|
pub mod versions;
|
||||||
|
|
||||||
|
pub struct Api {
|
||||||
|
version: Arc<Version>,
|
||||||
|
items: Items,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Api {
|
||||||
|
pub fn new(version: Version) -> Self {
|
||||||
|
let version = Arc::new(version);
|
||||||
|
Self {
|
||||||
|
version: Arc::clone(&version),
|
||||||
|
items: Items::new(Arc::clone(&version)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
use crate::api::tests::{get_api, get_test_versions};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_items_array() {
|
||||||
|
let versions = get_test_versions();
|
||||||
|
|
||||||
|
for version in versions {
|
||||||
|
let api = get_api(version);
|
||||||
|
assert_ne!(api.items.items_array().unwrap().len(), 0)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
use crate::api::versions::{available_versions, versions};
|
||||||
|
use crate::api::Api;
|
||||||
|
use crate::models::version::Version;
|
||||||
|
|
||||||
|
mod items;
|
||||||
|
mod versions;
|
||||||
|
|
||||||
|
fn get_api(version: Version) -> Api {
|
||||||
|
Api::new(version)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_test_versions() -> Vec<Version> {
|
||||||
|
let available = available_versions().unwrap();
|
||||||
|
versions()
|
||||||
|
.unwrap()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|v| available.contains(&v.minecraft_version))
|
||||||
|
.collect()
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
use crate::api::versions::{latest_stable, versions, versions_by_minecraft_version};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_versions() {
|
||||||
|
let unordered_versions = versions().unwrap();
|
||||||
|
assert_ne!(unordered_versions.len(), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_versions_by_minecraft_version() {
|
||||||
|
let versions = versions_by_minecraft_version().unwrap();
|
||||||
|
assert!(versions.get("1.16").is_some());
|
||||||
|
assert!(versions.get("1.14.12").is_none());
|
||||||
|
assert_eq!(versions.get("1.16.3").unwrap().major_version, "1.16")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_latest_stable_version() {
|
||||||
|
assert!(latest_stable().is_ok())
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
use crate::data::{get_common_file, PROTOCOL_VERSIONS_FILE, VERSIONS_FILE};
|
||||||
|
use crate::models::version::Version;
|
||||||
|
use crate::{DataError, DataResult};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
|
/// Returns the unsorted list of versions
|
||||||
|
pub fn versions() -> DataResult<Vec<Version>> {
|
||||||
|
let content = get_common_file(PROTOCOL_VERSIONS_FILE)?;
|
||||||
|
let versions = serde_json::from_str::<Vec<Version>>(&*content)?;
|
||||||
|
|
||||||
|
Ok(versions)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the versions indexed by minecraft version
|
||||||
|
pub fn versions_by_minecraft_version() -> DataResult<HashMap<String, Version>> {
|
||||||
|
let indexed_versions = HashMap::from_iter(
|
||||||
|
versions()?
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| (v.minecraft_version.clone(), v)),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(indexed_versions)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the latest stable version (hardcoded at the moment)
|
||||||
|
pub fn latest_stable() -> DataResult<Version> {
|
||||||
|
versions_by_minecraft_version()?
|
||||||
|
.get("1.16.5")
|
||||||
|
.cloned()
|
||||||
|
.ok_or(DataError::NotFoundError("1.16.5".to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list of available version information
|
||||||
|
pub(crate) fn available_versions() -> DataResult<Vec<String>> {
|
||||||
|
Ok(get_common_file(VERSIONS_FILE)?
|
||||||
|
.split_whitespace()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect())
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
use crate::models::version::Version;
|
||||||
|
use crate::{DataError, DataResult};
|
||||||
|
use include_dir::Dir;
|
||||||
|
|
||||||
|
pub static MINECRAFT_DATA: Dir = include_dir::include_dir!("minecraft-data/data/pc");
|
||||||
|
|
||||||
|
pub static BIOMES_FILE: &str = "biomes.json";
|
||||||
|
pub static BLOCK_LOOT_FILE: &str = "blockLoot.json";
|
||||||
|
pub static BLOCKS_FILE: &str = "blocks.json";
|
||||||
|
pub static COMMANDS_FILE: &str = "commands.json";
|
||||||
|
pub static ENTITIES_FILE: &str = "entities.json";
|
||||||
|
pub static ENTITY_LOOT_FILE: &str = "entityLoot.json";
|
||||||
|
pub static ITEMS_FILE: &str = "items.json";
|
||||||
|
pub static LOGIN_PACKET_FILE: &str = "loginPacket.json";
|
||||||
|
pub static MATERIALS_FILE: &str = "materials.json";
|
||||||
|
pub static PROTOCOL_FILE: &str = "protocol.json";
|
||||||
|
pub static RECIPES_FILE: &str = "recipes.json";
|
||||||
|
pub static TINTS_FILE: &str = "tints.json";
|
||||||
|
// pub static VERSION_FILE: &str = "version.json";
|
||||||
|
pub static MAP_ICONS_FILE: &str = "mapIcons.json";
|
||||||
|
pub static PARTICLES_FILE: &str = "particles.json";
|
||||||
|
pub static PROTOCOL_VERSIONS_FILE: &str = "protocolVersions.json";
|
||||||
|
pub static VERSIONS_FILE: &str = "versions.json";
|
||||||
|
|
||||||
|
/// Returns the string encoded content of the common file
|
||||||
|
pub fn get_common_file(filename: &str) -> DataResult<String> {
|
||||||
|
MINECRAFT_DATA
|
||||||
|
.get_file(format!("common/{}", filename))
|
||||||
|
.ok_or(DataError::NotFoundError(filename.to_string()))?
|
||||||
|
.contents_utf8()
|
||||||
|
.ok_or(DataError::InvalidEncodingError(filename.to_string()))
|
||||||
|
.map(|d| d.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the string encoded content of the version specific file
|
||||||
|
pub fn get_version_specific_file(version: &Version, filename: &str) -> DataResult<String> {
|
||||||
|
let search_folders = vec![
|
||||||
|
version.minecraft_version.clone(),
|
||||||
|
version.major_version.clone(),
|
||||||
|
version.major_first(),
|
||||||
|
version.previous_major(),
|
||||||
|
version.previous_major_first(),
|
||||||
|
];
|
||||||
|
println!("{:?}", search_folders);
|
||||||
|
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
|
||||||
|
)))?
|
||||||
|
.contents_utf8()
|
||||||
|
.ok_or(DataError::InvalidEncodingError(filename.to_string()))
|
||||||
|
.map(|d| d.to_string())
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate include_dir;
|
||||||
|
|
||||||
|
pub mod api;
|
||||||
|
pub(crate) mod data;
|
||||||
|
pub mod models;
|
||||||
|
pub(crate) mod utils;
|
||||||
|
|
||||||
|
pub use utils::error::DataError;
|
||||||
|
pub use utils::error::DataResult;
|
@ -0,0 +1,15 @@
|
|||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
|
#[serde(rename_all(deserialize = "camelCase", serialize = "snake_case"))]
|
||||||
|
pub struct Item {
|
||||||
|
pub id: u32,
|
||||||
|
pub display_name: String,
|
||||||
|
pub stack_size: u8,
|
||||||
|
pub enchant_categories: Option<Vec<String>>,
|
||||||
|
pub fixed_with: Option<Vec<String>>,
|
||||||
|
pub max_durability: Option<u32>,
|
||||||
|
pub name: String,
|
||||||
|
pub variations: Option<Value>,
|
||||||
|
pub durability: Option<u32>,
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
pub mod item;
|
||||||
|
pub mod version;
|
@ -0,0 +1,28 @@
|
|||||||
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
|
#[serde(rename_all(deserialize = "camelCase", serialize = "snake_case"))]
|
||||||
|
pub struct Version {
|
||||||
|
pub version: i32,
|
||||||
|
pub minecraft_version: String,
|
||||||
|
pub major_version: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Version {
|
||||||
|
/// Returns the first version of the current major version
|
||||||
|
pub(crate) fn major_first(&self) -> String {
|
||||||
|
format!("{}.1", self.major_version)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the previous major version
|
||||||
|
pub(crate) fn previous_major(&self) -> String {
|
||||||
|
let major = self.major_version.split('.').last().unwrap();
|
||||||
|
let major_num = major.parse::<i32>().unwrap();
|
||||||
|
|
||||||
|
self.major_version
|
||||||
|
.replace(major, format!("{}", major_num - 1).as_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the first version of the previous major version
|
||||||
|
pub(crate) fn previous_major_first(&self) -> String {
|
||||||
|
format!("{}.1", self.previous_major())
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
use std::io;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
pub type DataResult<T> = Result<T, DataError>;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum DataError {
|
||||||
|
#[error("IO Error: {0}")]
|
||||||
|
IOError(#[from] io::Error),
|
||||||
|
|
||||||
|
#[error("JSON Error: {0}")]
|
||||||
|
JsonError(#[from] serde_json::Error),
|
||||||
|
|
||||||
|
#[error("Object {0} not found")]
|
||||||
|
NotFoundError(String),
|
||||||
|
|
||||||
|
#[error("Invalid encoding of file {0}")]
|
||||||
|
InvalidEncodingError(String),
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
pub mod error;
|
Loading…
Reference in New Issue