use std::{
fmt::Debug,
path::{Path, PathBuf},
time::Duration,
};
use lighty_core::AppState;
use lighty_loaders::types::VersionInfo;
use lighty_modsloader::{ModRequest, WithMods};
#[cfg(any(feature = "modrinth", feature = "curseforge"))]
use lighty_modsloader::ModpackSource;
#[derive(Debug, Clone)]
pub struct VersionBuilder<L = ()> {
pub name: String,
pub loader: L,
pub loader_version: String,
pub minecraft_version: String,
pub game_dirs: PathBuf,
pub java_dirs: PathBuf,
pub runtime_dir: PathBuf,
pub mod_requests: Vec<ModRequest>,
#[cfg(any(feature = "modrinth", feature = "curseforge"))]
pub modpack: Option<ModpackSource>,
pub ttl_override: Option<Duration>,
}
impl<L> VersionBuilder<L> {
pub fn new(
name: &str,
loader: L,
loader_version: &str,
minecraft_version: &str,
) -> Self {
let game_dirs = AppState::data_dir().join(name);
let java_dirs = AppState::config_dir().join("jre");
Self {
name: name.to_string(),
loader,
loader_version: loader_version.to_string(),
minecraft_version: minecraft_version.to_string(),
runtime_dir: game_dirs.clone(),
game_dirs,
java_dirs,
mod_requests: Vec::new(),
#[cfg(any(feature = "modrinth", feature = "curseforge"))]
modpack: None,
ttl_override: None,
}
}
pub fn with_mod(self) -> ModSourcesBuilder<L> {
ModSourcesBuilder {
parent: self,
pending: Vec::new(),
#[cfg(any(feature = "modrinth", feature = "curseforge"))]
pending_modpack: None,
}
}
pub fn with_custom_java_dir(mut self, java_dir: PathBuf) -> Self {
self.java_dirs = java_dir;
self
}
pub fn with_loader(mut self, loader: L) -> Self {
self.loader = loader;
self
}
pub fn with_loader_version(mut self, version: &str) -> Self {
self.loader_version = version.to_string();
self
}
pub fn with_minecraft_version(mut self, version: &str) -> Self {
self.minecraft_version = version.to_string();
self
}
pub fn with_ttl_duration(mut self, ttl: Duration) -> Self {
self.ttl_override = Some(ttl);
self
}
}
impl<L: Clone + Send + Sync + Debug> VersionInfo for VersionBuilder<L> {
type LoaderType = L;
fn name(&self) -> &str {
&self.name
}
fn loader_version(&self) -> &str {
&self.loader_version
}
fn minecraft_version(&self) -> &str {
&self.minecraft_version
}
fn game_dirs(&self) -> &Path {
&self.game_dirs
}
fn java_dirs(&self) -> &Path {
&self.java_dirs
}
fn loader(&self) -> &Self::LoaderType {
&self.loader
}
fn runtime_dir(&self) -> &Path {
&self.runtime_dir
}
fn set_runtime_dir(&mut self, path: PathBuf) {
self.runtime_dir = path;
}
fn ttl(&self) -> Duration {
self.ttl_override.unwrap_or(Duration::from_secs(86_400))
}
}
impl<'b, L: Clone + Send + Sync + Debug> VersionInfo for &'b VersionBuilder<L> {
type LoaderType = L;
fn name(&self) -> &str {
&self.name
}
fn loader_version(&self) -> &str {
&self.loader_version
}
fn minecraft_version(&self) -> &str {
&self.minecraft_version
}
fn game_dirs(&self) -> &Path {
&self.game_dirs
}
fn java_dirs(&self) -> &Path {
&self.java_dirs
}
fn loader(&self) -> &Self::LoaderType {
&self.loader
}
fn runtime_dir(&self) -> &Path {
&self.runtime_dir
}
fn ttl(&self) -> Duration {
self.ttl_override.unwrap_or(Duration::from_secs(86_400))
}
}
impl<L: Clone + Send + Sync + Debug> WithMods for VersionBuilder<L> {
fn mod_requests(&self) -> &[ModRequest] {
&self.mod_requests
}
#[cfg(any(feature = "modrinth", feature = "curseforge"))]
fn modpack(&self) -> Option<&ModpackSource> {
self.modpack.as_ref()
}
}
impl<'b, L: Clone + Send + Sync + Debug> WithMods for &'b VersionBuilder<L> {
fn mod_requests(&self) -> &[ModRequest] {
&self.mod_requests
}
#[cfg(any(feature = "modrinth", feature = "curseforge"))]
fn modpack(&self) -> Option<&ModpackSource> {
self.modpack.as_ref()
}
}
pub struct ModSourcesBuilder<L> {
parent: VersionBuilder<L>,
pending: Vec<ModRequest>,
#[cfg(any(feature = "modrinth", feature = "curseforge"))]
pending_modpack: Option<ModpackSource>,
}
impl<L> ModSourcesBuilder<L> {
#[cfg(feature = "modrinth")]
pub fn with_modrinth_mods<S>(mut self, list: Vec<(S, Option<String>)>) -> Self
where
S: Into<String>,
{
for (id_or_slug, version) in list {
self.pending.push(ModRequest::Modrinth {
id_or_slug: id_or_slug.into(),
version,
});
}
self
}
#[cfg(feature = "curseforge")]
pub fn with_curseforge_mods(mut self, list: Vec<(u32, Option<u32>)>) -> Self {
for (mod_id, file_id) in list {
self.pending.push(ModRequest::CurseForge { mod_id, file_id });
}
self
}
#[cfg(feature = "modrinth")]
pub fn with_modrinth_modpack(mut self, source: impl Into<ModpackSource>) -> Self {
self.pending_modpack = Some(source.into());
self
}
#[cfg(feature = "curseforge")]
pub fn with_curseforge_modpack(mut self, project_id: u32, file_id: u32) -> Self {
self.pending_modpack = Some(ModpackSource::CurseForgePinned { project_id, file_id });
self
}
pub fn done(self) -> VersionBuilder<L> {
let mut parent = self.parent;
let mut pending = self.pending;
parent.mod_requests.append(&mut pending);
#[cfg(any(feature = "modrinth", feature = "curseforge"))]
if self.pending_modpack.is_some() {
parent.modpack = self.pending_modpack;
}
parent
}
}