mirror of
https://github.com/Dummi26/musicdb.git
synced 2025-03-10 05:43:53 +01:00
fix features, add mers feature, improve merscfg, add run-mers mode
This commit is contained in:
parent
5ffd71f520
commit
d1f2db3e45
@ -12,9 +12,20 @@ musicdb-lib = { version = "0.1.0", path = "../musicdb-lib" }
|
||||
regex = "1.9.3"
|
||||
speedy2d = { version = "1.12.0", optional = true }
|
||||
toml = "0.7.6"
|
||||
mers_lib = { version = "0.3.1", optional = true }
|
||||
mers_lib = { version = "0.3.2", optional = true }
|
||||
musicdb-mers = { version = "0.1.0", path = "../musicdb-mers", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["speedy2d"]
|
||||
default = ["gui"]
|
||||
# gui:
|
||||
# enables the gui mode
|
||||
# merscfg:
|
||||
# allows using mers to configure the gui
|
||||
# mers:
|
||||
# enables the run-mers mode
|
||||
# playback:
|
||||
# enables Symcplayer modes, where the client mirrors the server's playback
|
||||
gui = ["speedy2d"]
|
||||
merscfg = ["mers_lib", "musicdb-mers", "speedy2d"]
|
||||
mers = ["mers_lib", "musicdb-mers"]
|
||||
playback = ["musicdb-lib/playback"]
|
||||
merscfg = ["mers_lib"]
|
||||
|
@ -39,6 +39,8 @@ use crate::{
|
||||
|
||||
pub enum GuiEvent {
|
||||
Refresh,
|
||||
#[cfg(feature = "merscfg")]
|
||||
RefreshMers,
|
||||
UpdatedQueue,
|
||||
UpdatedLibrary,
|
||||
Exit,
|
||||
@ -213,7 +215,7 @@ pub fn main(
|
||||
let sender = window.create_user_event_sender();
|
||||
window.run_loop(Gui::new(
|
||||
font,
|
||||
database,
|
||||
Arc::clone(&database),
|
||||
connection,
|
||||
Arc::new(Mutex::new(get_con)),
|
||||
event_sender_arc,
|
||||
@ -258,7 +260,7 @@ pub fn main(
|
||||
),
|
||||
],
|
||||
#[cfg(feature = "merscfg")]
|
||||
merscfg: crate::merscfg::MersCfg::new(config_dir.join("dynamic_config.mers")),
|
||||
merscfg: crate::merscfg::MersCfg::new(config_dir.join("dynamic_config.mers"), database),
|
||||
},
|
||||
));
|
||||
}
|
||||
@ -316,7 +318,8 @@ impl Gui {
|
||||
scroll_pixels_multiplier: f64,
|
||||
scroll_lines_multiplier: f64,
|
||||
scroll_pages_multiplier: f64,
|
||||
gui_config: GuiConfig,
|
||||
#[cfg(not(feature = "merscfg"))] gui_config: GuiConfig,
|
||||
#[cfg(feature = "merscfg")] mut gui_config: GuiConfig,
|
||||
) -> Self {
|
||||
let (notif_overlay, notif_sender) = NotifOverlay::new();
|
||||
let notif_sender_two = notif_sender.clone();
|
||||
@ -1195,13 +1198,14 @@ impl WindowHandler<GuiEvent> for Gui {
|
||||
Rectangle::new(Vec2::ZERO, self.size.into_f32()),
|
||||
Color::BLACK,
|
||||
);
|
||||
let mut cfg = self.gui_config.take().unwrap();
|
||||
// before the db is locked!
|
||||
#[cfg(feature = "merscfg")]
|
||||
MersCfg::run(&mut cfg, self, |m| &m.func_before_draw);
|
||||
let dblock = Arc::clone(&self.database);
|
||||
let mut dblock = dblock.lock().unwrap();
|
||||
let mut covers = self.covers.take().unwrap();
|
||||
let mut custom_images = self.custom_images.take().unwrap();
|
||||
let mut cfg = self.gui_config.take().unwrap();
|
||||
#[cfg(feature = "merscfg")]
|
||||
MersCfg::run(&mut cfg, self, Some(&mut dblock), |m| &m.func_before_draw);
|
||||
let mut info = DrawInfo {
|
||||
time: draw_start_time,
|
||||
actions: Vec::with_capacity(0),
|
||||
@ -1450,15 +1454,17 @@ impl WindowHandler<GuiEvent> for Gui {
|
||||
fn on_user_event(&mut self, helper: &mut WindowHelper<GuiEvent>, user_event: GuiEvent) {
|
||||
match user_event {
|
||||
GuiEvent::Refresh => helper.request_redraw(),
|
||||
#[cfg(feature = "merscfg")]
|
||||
GuiEvent::RefreshMers => {
|
||||
if let Some(mut cfg) = self.gui_config.take() {
|
||||
MersCfg::run(&mut cfg, self, |cfg| &crate::merscfg::OptFunc(None));
|
||||
self.gui_config = Some(cfg);
|
||||
}
|
||||
}
|
||||
GuiEvent::UpdatedLibrary => {
|
||||
#[cfg(feature = "merscfg")]
|
||||
if let Some(mut gc) = self.gui_config.take() {
|
||||
MersCfg::run(
|
||||
&mut gc,
|
||||
self,
|
||||
self.database.clone().lock().ok().as_mut().map(|v| &mut **v),
|
||||
|m| &m.func_library_updated,
|
||||
);
|
||||
MersCfg::run(&mut gc, self, |m| &m.func_library_updated);
|
||||
self.gui_config = Some(gc);
|
||||
} else {
|
||||
eprintln!("WARN: Skipping call to merscfg's library_updated because gui_config is not available");
|
||||
@ -1469,12 +1475,7 @@ impl WindowHandler<GuiEvent> for Gui {
|
||||
GuiEvent::UpdatedQueue => {
|
||||
#[cfg(feature = "merscfg")]
|
||||
if let Some(mut gc) = self.gui_config.take() {
|
||||
MersCfg::run(
|
||||
&mut gc,
|
||||
self,
|
||||
self.database.clone().lock().ok().as_mut().map(|v| &mut **v),
|
||||
|m| &m.func_queue_updated,
|
||||
);
|
||||
MersCfg::run(&mut gc, self, |m| &m.func_queue_updated);
|
||||
self.gui_config = Some(gc);
|
||||
} else {
|
||||
eprintln!("WARN: Skipping call to merscfg's queue_updated because gui_config is not available");
|
||||
|
@ -4,7 +4,6 @@ use std::{
|
||||
path::PathBuf,
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
@ -18,8 +17,9 @@ use musicdb_lib::{
|
||||
CoverId, SongId,
|
||||
},
|
||||
load::ToFromBytes,
|
||||
server::{get, Command},
|
||||
server::Command,
|
||||
};
|
||||
#[cfg(feature = "speedy2d")]
|
||||
use speedy2d::color::Color;
|
||||
#[cfg(feature = "speedy2d")]
|
||||
mod gui;
|
||||
@ -27,6 +27,7 @@ mod gui;
|
||||
mod gui_anim;
|
||||
#[cfg(feature = "speedy2d")]
|
||||
mod gui_base;
|
||||
#[cfg(feature = "speedy2d")]
|
||||
mod gui_edit_song;
|
||||
#[cfg(feature = "speedy2d")]
|
||||
mod gui_idle_display;
|
||||
@ -75,6 +76,8 @@ enum Mode {
|
||||
/// play in sync with the server, and fetch the songs from it too. slower than the local variant for obvious reasons
|
||||
#[cfg(feature = "playback")]
|
||||
SyncplayerNetwork,
|
||||
#[cfg(feature = "mers")]
|
||||
RunMers { path: PathBuf },
|
||||
}
|
||||
|
||||
fn get_config_file_path() -> PathBuf {
|
||||
@ -85,6 +88,10 @@ fn get_config_file_path() -> PathBuf {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
#[cfg(not(feature = "speedy2d"))]
|
||||
#[cfg(not(feature = "mers"))]
|
||||
#[cfg(not(feature = "playback"))]
|
||||
compile_error!("None of the optional features are enabled. Without at least one of these, the application is useless! See Cargo.toml for info.");
|
||||
// parse args
|
||||
let args = Args::parse();
|
||||
// start
|
||||
@ -132,7 +139,8 @@ fn main() {
|
||||
if let Some(player) = &mut player {
|
||||
let mut db = database.lock().unwrap();
|
||||
if db.is_client_init() {
|
||||
player.update(&mut db);
|
||||
// command_sender does nothing. if a song finishes, we don't want to move to the next song, we want to wait for the server to send the NextSong event.
|
||||
player.update(&mut db, &Arc::new(|_| {}));
|
||||
}
|
||||
}
|
||||
let update = Command::from_bytes(&mut con).unwrap();
|
||||
@ -154,7 +162,7 @@ fn main() {
|
||||
{
|
||||
let occasional_refresh_sender = Arc::clone(&sender);
|
||||
thread::spawn(move || loop {
|
||||
std::thread::sleep(Duration::from_secs(1));
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
if let Some(v) = &*occasional_refresh_sender.lock().unwrap() {
|
||||
v.send_event(GuiEvent::Refresh).unwrap();
|
||||
}
|
||||
@ -162,7 +170,7 @@ fn main() {
|
||||
gui::main(
|
||||
database,
|
||||
con,
|
||||
get::Client::new(BufReader::new(
|
||||
musicdb_lib::server::get::Client::new(BufReader::new(
|
||||
TcpStream::connect(addr).expect("opening get client connection"),
|
||||
))
|
||||
.expect("initializing get client connection"),
|
||||
@ -174,6 +182,38 @@ fn main() {
|
||||
Mode::SyncplayerLocal { .. } | Mode::SyncplayerNetwork => {
|
||||
con_thread.join().unwrap();
|
||||
}
|
||||
#[cfg(feature = "mers")]
|
||||
Mode::RunMers { path } => {
|
||||
let mut src = mers_lib::prelude_compile::Source::new_from_file(path).unwrap();
|
||||
let srca = Arc::new(src.clone());
|
||||
let con = Mutex::new(con);
|
||||
let (mut i1, mut i2, mut i3) = musicdb_mers::add(
|
||||
mers_lib::prelude_compile::Config::new().bundle_std(),
|
||||
&database,
|
||||
&Arc::new(move |cmd: Command| cmd.to_bytes(&mut *con.lock().unwrap()).unwrap()),
|
||||
)
|
||||
.infos();
|
||||
let program = mers_lib::prelude_compile::parse(&mut src, &srca)
|
||||
.unwrap()
|
||||
.compile(&mut i1, mers_lib::prelude_compile::CompInfo::default())
|
||||
.unwrap();
|
||||
match program.check(&mut i3, None) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
eprintln!("{e}");
|
||||
std::process::exit(60);
|
||||
}
|
||||
};
|
||||
// wait until db is synced
|
||||
let dur = std::time::Duration::from_secs_f32(0.1);
|
||||
loop {
|
||||
std::thread::sleep(dur);
|
||||
if database.lock().unwrap().is_client_init() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
program.run(&mut i2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,6 +238,7 @@ fn get_cover(song: SongId, database: &Database) -> Option<CoverId> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "speedy2d")]
|
||||
pub(crate) fn color_scale(c: Color, r: f32, g: f32, b: f32, new_alpha: Option<f32>) -> Color {
|
||||
Color::from_rgba(c.r() * r, c.g() * g, c.b() * b, new_alpha.unwrap_or(c.a()))
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ use crate::{
|
||||
textcfg::TextBuilder,
|
||||
};
|
||||
|
||||
pub struct OptFunc(Option<mers_lib::data::function::Function>);
|
||||
pub struct OptFunc(pub Option<mers_lib::data::function::Function>);
|
||||
impl OptFunc {
|
||||
pub fn none() -> Self {
|
||||
Self(None)
|
||||
@ -65,6 +65,7 @@ impl OptFunc {
|
||||
/// - `set_idle_screen_side_text_2_format`
|
||||
pub struct MersCfg {
|
||||
pub source_file: PathBuf,
|
||||
pub database: Arc<Mutex<Database>>,
|
||||
// - - handler functions - -
|
||||
pub func_before_draw: OptFunc,
|
||||
pub func_library_updated: OptFunc,
|
||||
@ -75,6 +76,10 @@ pub struct MersCfg {
|
||||
pub var_window_size_in_pixels: Arc<RwLock<Data>>,
|
||||
pub var_idle_screen_cover_aspect_ratio: Arc<RwLock<Data>>,
|
||||
// - - results from running functions - -
|
||||
pub channel_gui_actions: (
|
||||
std::sync::mpsc::Sender<Command>,
|
||||
std::sync::mpsc::Receiver<Command>,
|
||||
),
|
||||
pub updated_playing_status: Arc<AtomicU8>,
|
||||
pub updated_idle_status: Arc<AtomicU8>,
|
||||
pub updated_idle_screen_cover_pos: Arc<Updatable<Option<Rectangle>>>,
|
||||
@ -90,9 +95,10 @@ pub struct MersCfg {
|
||||
}
|
||||
|
||||
impl MersCfg {
|
||||
pub fn new(path: PathBuf) -> Self {
|
||||
pub fn new(path: PathBuf, database: Arc<Mutex<Database>>) -> Self {
|
||||
Self {
|
||||
source_file: path,
|
||||
database,
|
||||
|
||||
func_before_draw: OptFunc::none(),
|
||||
func_library_updated: OptFunc::none(),
|
||||
@ -110,6 +116,7 @@ impl MersCfg {
|
||||
mers_lib::data::float::Float(0.0),
|
||||
))),
|
||||
|
||||
channel_gui_actions: std::sync::mpsc::channel(),
|
||||
updated_playing_status: Arc::new(AtomicU8::new(0)),
|
||||
updated_idle_status: Arc::new(AtomicU8::new(0)),
|
||||
updated_idle_screen_cover_pos: Arc::new(Updatable::new()),
|
||||
@ -127,12 +134,19 @@ impl MersCfg {
|
||||
fn custom_globals(
|
||||
&self,
|
||||
cfg: mers_lib::prelude_extend_config::Config,
|
||||
db: &Arc<Mutex<Database>>,
|
||||
event_sender: Arc<UserEventSender<GuiEvent>>,
|
||||
notif_sender: Sender<
|
||||
Box<dyn FnOnce(&NotifOverlay) -> (Box<dyn GuiElem>, NotifInfo) + Send>,
|
||||
>,
|
||||
) -> mers_lib::prelude_extend_config::Config {
|
||||
cfg.add_var_arc(
|
||||
let cmd_es = event_sender.clone();
|
||||
let cmd_ga = self.channel_gui_actions.0.clone();
|
||||
musicdb_mers::add(cfg, db, &Arc::new(move |cmd| {
|
||||
cmd_ga.send(cmd).unwrap();
|
||||
cmd_es.send_event(GuiEvent::RefreshMers).unwrap();
|
||||
}))
|
||||
.add_var_arc(
|
||||
"is_playing".to_owned(),
|
||||
Arc::clone(&self.var_is_playing),
|
||||
self.var_is_playing.read().unwrap().get().as_type(),
|
||||
@ -545,14 +559,11 @@ impl MersCfg {
|
||||
// ]))))
|
||||
}
|
||||
|
||||
pub fn run(
|
||||
gui_cfg: &mut GuiConfig,
|
||||
gui: &mut Gui,
|
||||
mut db: Option<&mut Database>,
|
||||
run: impl FnOnce(&Self) -> &OptFunc,
|
||||
) {
|
||||
// prepare vars
|
||||
if let Some(db) = &mut db {
|
||||
pub fn run(gui_cfg: &mut GuiConfig, gui: &mut Gui, run: impl FnOnce(&Self) -> &OptFunc) {
|
||||
{
|
||||
let mut db = gui_cfg.merscfg.database.lock().unwrap();
|
||||
let db = &mut db;
|
||||
// prepare vars
|
||||
*gui_cfg.merscfg.var_is_playing.write().unwrap() =
|
||||
mers_lib::data::Data::new(mers_lib::data::bool::Bool(db.playing));
|
||||
}
|
||||
@ -572,6 +583,14 @@ impl MersCfg {
|
||||
// run
|
||||
run(&gui_cfg.merscfg).run();
|
||||
|
||||
loop {
|
||||
if let Ok(a) = gui_cfg.merscfg.channel_gui_actions.1.try_recv() {
|
||||
gui.exec_gui_action(GuiAction::SendToServer(a));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// apply updates
|
||||
|
||||
match gui_cfg
|
||||
@ -701,6 +720,7 @@ impl MersCfg {
|
||||
let (mut i1, mut i2, mut i3) = self
|
||||
.custom_globals(
|
||||
mers_lib::prelude_extend_config::Config::new().bundle_std(),
|
||||
&self.database,
|
||||
event_sender,
|
||||
notif_sender,
|
||||
)
|
||||
|
@ -1,6 +1,5 @@
|
||||
use std::{
|
||||
collections::{BTreeSet, HashMap, HashSet},
|
||||
convert::identity,
|
||||
collections::{BTreeSet, HashMap},
|
||||
fs::{self, File},
|
||||
io::{BufReader, Read, Write},
|
||||
path::PathBuf,
|
||||
|
Loading…
Reference in New Issue
Block a user