From d83f9dc80ab9ff4a3e2c5bc2b58c784a9172c15c Mon Sep 17 00:00:00 2001 From: Murilo Matsubara Date: Thu, 20 Apr 2023 12:08:04 -0300 Subject: [PATCH] Add configs.json support --- .gitignore | 3 +- Cargo.lock | 38 +++++++++++++++++++++-- Cargo.toml | 5 +++- src/configs.rs | 70 +++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/main.rs | 23 ++++++++++++-- src/osu.rs | 4 +-- src/song_selection.rs | 48 +++++++++++++---------------- 8 files changed, 157 insertions(+), 35 deletions(-) create mode 100644 src/configs.rs diff --git a/.gitignore b/.gitignore index c41cc9e..39ad715 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/target \ No newline at end of file +/target +configs.json \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 0d31bc6..382237f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -127,6 +127,17 @@ dependencies = [ "syn 2.0.15", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -503,6 +514,17 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688" +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + [[package]] name = "combine" version = "4.6.6" @@ -976,6 +998,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.2.6" @@ -1471,7 +1502,7 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] @@ -1558,15 +1589,18 @@ dependencies = [ [[package]] name = "osucraft" -version = "0.1.0" +version = "0.1.1" dependencies = [ "anyhow", "bevy_ecs", + "colored", "directories", "fuzzy-matcher", "osu-file-parser", "rand", "rodio", + "serde", + "serde_json", "tracing", "tracing-subscriber", "valence", diff --git a/Cargo.toml b/Cargo.toml index 3cad44f..f8eea41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "osucraft" -version = "0.1.0" +version = "0.1.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -8,11 +8,14 @@ edition = "2021" [dependencies] anyhow = "1.0.68" bevy_ecs = "0.9.1" +colored = "2.0.0" directories = "5.0.0" fuzzy-matcher = "0.3.7" osu-file-parser = "1.1.0" rand = "0.8.5" rodio = "0.17.1" +serde = "1.0.160" +serde_json = "1.0.96" tracing = "0.1.37" tracing-subscriber = "0.3.16" valence = { git = "https://github.com/mymatsubara/valence", branch = "osucraft" } diff --git a/src/configs.rs b/src/configs.rs new file mode 100644 index 0000000..88b20ee --- /dev/null +++ b/src/configs.rs @@ -0,0 +1,70 @@ +use anyhow::Result; +use colored::Colorize; +use directories::BaseDirs; +use std::fmt::Display; +use std::str; +use std::{fs, path::PathBuf}; + +use bevy_ecs::system::Resource; +use serde::{Deserialize, Serialize}; +use tracing::warn; + +#[derive(Resource, Serialize, Deserialize, Debug)] +pub struct Configs { + songs_directory: String, +} + +impl Configs { + pub fn open() -> Self { + Self::read().unwrap_or_else(|_| { + let default_configs = Self::default(); + + if let Err(error) = default_configs.save() { + warn!("Error while saving configs file: {}", error); + } + + default_configs + }) + } + + pub fn path() -> PathBuf { + PathBuf::from("configs.json") + } + + fn read() -> Result { + let path = Self::path(); + let file_data = fs::read(path)?; + let json = str::from_utf8(file_data.as_slice())?; + Ok(serde_json::from_str(json)?) + } + + fn save(&self) -> Result<()> { + let json = serde_json::to_string_pretty(self)?; + fs::write(Self::path(), json)?; + + Ok(()) + } + + pub fn songs_directory(&self) -> &str { + &self.songs_directory + } +} + +impl Default for Configs { + fn default() -> Self { + let local_dir = BaseDirs::new() + .map(|base_dirs| base_dirs.data_local_dir().to_path_buf()) + .unwrap_or_else(|| PathBuf::from("./")); + let songs_directory = local_dir.join("osu!").join("Songs"); + + Self { + songs_directory: songs_directory.to_str().unwrap().to_owned(), + } + } +} + +impl Display for Configs { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}: {}", "Songs directory".cyan(), self.songs_directory) + } +} diff --git a/src/lib.rs b/src/lib.rs index 92a5ded..7d06ed6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ pub mod beatmap; pub mod beatmap_selection; pub mod color; pub mod commands; +pub mod configs; pub mod digit; pub mod hit_object; pub mod hit_score; diff --git a/src/main.rs b/src/main.rs index e9dd166..88996a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,9 @@ +use std::path::PathBuf; + +use colored::Colorize; use osucraft::audio::AudioPlayer; +use osucraft::configs::Configs; use osucraft::osu::{Osu, OsuInstance}; use osucraft::plugin::OsuPlugin; use rodio::OutputStream; @@ -36,16 +40,31 @@ pub fn main() { } fn setup(world: &mut World) { + // Init configs + let configs = Configs::open(); + let configs_path = Configs::path(); + let header = format!( + "================= CONFIGS ({}) =================", + configs_path.display() + ); + println!("{}", header.cyan()); + println!("{configs}\n"); + let info = format!( + "INFO: To update any config modify the file '{}' and restart the server.\n", + configs_path.display() + ); + println!("{}", info.yellow()); + let server = world.resource::(); let mut instance = server.new_instance(DimensionId::default()); // Init osu world.resource::().init(&mut instance); - Osu::init_inventory_selections(world); + Osu::init_inventory_selections(world, PathBuf::from(configs.songs_directory())); world.spawn((instance, OsuInstance)); - println!("Server is running on: \x1b[32mlocalhost:25565\x1b[0m") + println!("Server is running on: {}", "localhost::25565".green()) } fn init_clients( diff --git a/src/osu.rs b/src/osu.rs index acfd43d..09c716f 100644 --- a/src/osu.rs +++ b/src/osu.rs @@ -248,8 +248,8 @@ impl Osu { instance.set_block(block_pos, Block::new(BlockState::BEDROCK)); } - pub fn init_inventory_selections(world: &mut World) { - match SongSelectionInventory::new() { + pub fn init_inventory_selections(world: &mut World, songs_dir: PathBuf) { + match SongSelectionInventory::new(songs_dir) { Ok(song_selection) => { world.spawn(song_selection); } diff --git a/src/song_selection.rs b/src/song_selection.rs index b499fb6..c1b40da 100644 --- a/src/song_selection.rs +++ b/src/song_selection.rs @@ -1,5 +1,4 @@ use anyhow::{anyhow, Result}; -use directories::BaseDirs; use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher}; use std::{ cmp::{min, Reverse}, @@ -36,6 +35,7 @@ const PAGE_SIZE: usize = 36; pub struct SongSelectionInventory { cur_page: usize, songs: Vec, + songs_dir: PathBuf, keywords: Option, } @@ -45,17 +45,18 @@ struct Song { } impl SongSelectionInventory { - pub fn new() -> Result<(Self, Inventory)> { + pub fn new(songs_dir: PathBuf) -> Result<(Self, Inventory)> { let inventory = Inventory::new(InventoryKind::Generic9x6); - Ok(( - Self { - cur_page: 0, - songs: Self::get_all_songs()?, - keywords: None, - }, - inventory, - )) + let mut result = Self { + cur_page: 0, + songs_dir, + songs: Default::default(), + keywords: None, + }; + result.songs = result.fetch_all_songs()?; + + Ok((result, inventory)) } pub fn go_to_next_page(&mut self) { @@ -67,7 +68,7 @@ impl SongSelectionInventory { } pub fn set_filter(&mut self, keywords: Option<&str>) -> Result<()> { - self.songs = Self::filter_songs(Self::get_all_songs()?, keywords); + self.songs = Self::filter_songs(self.fetch_all_songs()?, keywords); self.keywords = keywords.map(|s| s.to_string()); self.cur_page = 0; @@ -107,8 +108,15 @@ impl SongSelectionInventory { (self.songs.len() - 1) / PAGE_SIZE } - fn get_all_songs() -> Result> { - Ok(read_dir(Self::get_songs_dir()?)? + fn fetch_all_songs(&self) -> Result> { + if !self.songs_dir.exists() { + return Err(anyhow!( + "Could not find osu! song directory: '{}'.", + self.songs_dir.display() + )); + } + + Ok(read_dir(self.songs_dir.clone())? .filter_map(|result| result.ok()) .map(|entry| entry.path()) .filter(|entry| entry.is_dir() && entry.file_name().is_some()) @@ -140,20 +148,6 @@ impl SongSelectionInventory { None => songs, } } - - fn get_songs_dir() -> Result { - let base_dirs = BaseDirs::new().ok_or(anyhow!("No home directory found in the system"))?; - let beatmaps_dir = base_dirs.data_local_dir().join("osu!").join("Songs"); - - if beatmaps_dir.exists() { - Ok(beatmaps_dir) - } else { - Err(anyhow!( - "Could not find osu song directory: '{}'", - beatmaps_dir.display() - )) - } - } } pub fn update_song_selection_inventory(