From 2980a3f5b85167cd03a9030a94f7cf3842707cbc Mon Sep 17 00:00:00 2001 From: matcool <26722564+matcool@users.noreply.github.com> Date: Sat, 15 Oct 2022 22:06:06 -0300 Subject: [PATCH] run cargo fmt and fix most clippy warnings the code before had a horrible mix of spaces and tabs everywhere, even on the same line!!!! so now use tabs for everything since that seemed to be the dominant indentation style also change some of the code as suggested by clippy --- Cargo.lock | 2 +- Cargo.toml | 2 +- build.rs | 15 ++- rustfmt.toml | 1 + src/info.rs | 78 +++++++------ src/main.rs | 117 ++++++++++--------- src/package.rs | 246 ++++++++++++++++++++++++---------------- src/profile.rs | 44 +++---- src/sdk.rs | 161 +++++++++++++++----------- src/template.rs | 211 +++++++++++++++++----------------- src/util/bmfont.rs | 144 +++++++++++------------ src/util/cache.rs | 111 ++++++++++-------- src/util/config.rs | 83 ++++++++------ src/util/logging.rs | 14 +-- src/util/mod.rs | 4 +- src/util/mod_file.rs | 138 ++++++++++++++-------- src/util/rgba4444.rs | 24 ++-- src/util/spritesheet.rs | 109 ++++++++++-------- 18 files changed, 845 insertions(+), 659 deletions(-) create mode 100644 rustfmt.toml diff --git a/Cargo.lock b/Cargo.lock index a375cf6..32079ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -575,7 +575,7 @@ dependencies = [ [[package]] name = "geode" -version = "1.0.6" +version = "1.0.7" dependencies = [ "clap", "colored", diff --git a/Cargo.toml b/Cargo.toml index ba4bb96..9257745 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "geode" -version = "1.0.6" +version = "1.0.7" authors = ["HJfod ", "Camila314 "] edition = "2021" build = "build.rs" diff --git a/build.rs b/build.rs index 3458c78..72ef885 100644 --- a/build.rs +++ b/build.rs @@ -1,8 +1,11 @@ -#[cfg(windows)] extern crate winres; +#[cfg(windows)] +extern crate winres; + fn main() { - #[cfg(windows)] { - let mut res = winres::WindowsResource::new(); - res.set_icon("geode.ico"); - res.compile().unwrap(); - } + #[cfg(windows)] + { + let mut res = winres::WindowsResource::new(); + res.set_icon("geode.ico"); + res.compile().unwrap(); + } } diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..218e203 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +hard_tabs = true diff --git a/src/info.rs b/src/info.rs index 9533a2c..9a5347a 100644 --- a/src/info.rs +++ b/src/info.rs @@ -1,15 +1,15 @@ -use std::cell::RefCell; -use std::io::BufRead; -/** - * geode info - */ -use std::path::{PathBuf}; use crate::config::Config; use crate::util::config::Profile; -use crate::{fail, done, info}; use crate::NiceUnwrap; -use colored::Colorize; +use crate::{done, fail, info}; use clap::Subcommand; +use colored::Colorize; +use std::cell::RefCell; +use std::io::BufRead; +/** + * geode info + */ +use std::path::PathBuf; #[derive(Subcommand, Debug)] pub enum Info { @@ -19,7 +19,7 @@ pub enum Info { field: String, /// New value - value: String + value: String, }, /// Get value @@ -29,9 +29,9 @@ pub enum Info { /// Output raw value #[clap(long)] - raw: bool + raw: bool, }, - + /// List possible values List, @@ -39,11 +39,7 @@ pub enum Info { Setup {}, } -const CONFIGURABLES: [&str; 3] = [ - "default-developer", - "sdk-path", - "sdk-nightly" -]; +const CONFIGURABLES: [&str; 3] = ["default-developer", "sdk-path", "sdk-nightly"]; fn get_bool(value: &str) -> Option { let lower = value.to_ascii_lowercase(); @@ -65,15 +61,15 @@ pub fn subcommand(config: &mut Config, cmd: Info) { if field == "default-developer" { config.default_developer = Some(value); } else if field == "sdk-nightly" { - config.sdk_nightly = get_bool(&value) - .nice_unwrap(format!("'{}' cannot be parsed as a bool", value)); + config.sdk_nightly = + get_bool(&value).nice_unwrap(format!("'{}' cannot be parsed as a bool", value)); } else { fail!("Unknown field {}", field); return; } done!("{}", done_str); - }, + } Info::Get { field, raw } => { let sdk_path; @@ -89,13 +85,11 @@ pub fn subcommand(config: &mut Config, cmd: Info) { } else { "false" } + } else if raw { + std::process::exit(1); } else { - if raw { - std::process::exit(1); - } else { - fail!("Unknown field {}", field); - return; - } + fail!("Unknown field {}", field); + return; }; if raw { @@ -103,28 +97,28 @@ pub fn subcommand(config: &mut Config, cmd: Info) { } else { println!("{} = {}", field.bright_cyan(), out.bright_green()); } - }, + } Info::List => { for i in CONFIGURABLES { println!("{}", i); } - }, + } Info::Setup {} => { if config.profiles.is_empty() { info!("Please enter the path to the Geometry Dash folder:"); - + let path = loop { let mut buf = String::new(); match std::io::stdin().lock().read_line(&mut buf) { - Ok(_) => {}, + Ok(_) => {} Err(e) => { fail!("Unable to read input: {}", e); continue; } }; - + // Verify path is valid let path = PathBuf::from(buf.trim()); if !path.is_dir() { @@ -134,11 +128,15 @@ pub fn subcommand(config: &mut Config, cmd: Info) { ); continue; } - if path.read_dir().map(|mut files| files.next().is_none()).unwrap_or(false) { + if path + .read_dir() + .map(|mut files| files.next().is_none()) + .unwrap_or(false) + { fail!("Given path appears to be empty"); continue; } - // todo: maybe do some checksum verification + // todo: maybe do some checksum verification // to make sure GD 2.113 is in the folder break path; }; @@ -148,20 +146,20 @@ pub fn subcommand(config: &mut Config, cmd: Info) { let mut buf = String::new(); match std::io::stdin().lock().read_line(&mut buf) { Ok(_) => break buf, - Err(e) => fail!("Unable to read input: {}", e) + Err(e) => fail!("Unable to read input: {}", e), }; }; - - config.profiles.push(RefCell::new( - Profile::new(name.trim().into(), path) - )); + + config + .profiles + .push(RefCell::new(Profile::new(name.trim().into(), path))); config.current_profile = Some(name.trim().into()); done!("Profile added"); } config.sdk_nightly = Config::sdk_path().join("bin/nightly").exists(); - + done!("Config setup finished"); - }, + } } -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index 71c70eb..d22f469 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use clap::{Parser, Subcommand}; /** * geode new: Create new geode project from template * geode info: Subcommand for listing information about the current state @@ -7,14 +8,13 @@ * geode install: alias of `geode package install` */ use std::path::PathBuf; -use clap::{Parser, Subcommand}; -mod util; -mod template; +mod info; mod package; mod profile; -mod info; mod sdk; +mod template; +mod util; use util::*; @@ -22,73 +22,72 @@ use util::*; #[derive(Parser, Debug)] #[clap(version)] struct Args { - #[clap(subcommand)] - command: GeodeCommands + #[clap(subcommand)] + command: GeodeCommands, } #[derive(Subcommand, Debug)] enum GeodeCommands { - /// Create template mod project - New { - /// Mod project directory - #[clap(short, long)] - path: Option, - - /// Mod name - #[clap(short, long)] - name: Option - }, - - /// Install a .geode package to current profile, alias of `geode package install` - Install { - /// Location of the .geode package to install - path: PathBuf - }, - - /// Subcommand for managing profiles - Profile { - #[clap(subcommand)] - commands: crate::profile::Profile - }, - - /// Subcommand for managing configurable data - Config { - #[clap(subcommand)] - commands: crate::info::Info - }, - - /// Subcommand for managing the Geode SDK - Sdk { - #[clap(subcommand)] - commands: crate::sdk::Sdk - }, - - /// Subcommand for managing Geode packages - Package { - #[clap(subcommand)] - commands: crate::package::Package - } + /// Create template mod project + New { + /// Mod project directory + #[clap(short, long)] + path: Option, + + /// Mod name + #[clap(short, long)] + name: Option, + }, + + /// Install a .geode package to current profile, alias of `geode package install` + Install { + /// Location of the .geode package to install + path: PathBuf, + }, + + /// Subcommand for managing profiles + Profile { + #[clap(subcommand)] + commands: crate::profile::Profile, + }, + + /// Subcommand for managing configurable data + Config { + #[clap(subcommand)] + commands: crate::info::Info, + }, + + /// Subcommand for managing the Geode SDK + Sdk { + #[clap(subcommand)] + commands: crate::sdk::Sdk, + }, + + /// Subcommand for managing Geode packages + Package { + #[clap(subcommand)] + commands: crate::package::Package, + }, } - fn main() { - let args = Args::parse(); + let args = Args::parse(); + + let mut config = config::Config::new(); - let mut config = config::Config::new(); + match args.command { + GeodeCommands::New { name, path } => template::build_template(&mut config, name, path), - match args.command { - GeodeCommands::New { name, path} => template::build_template(&mut config, name, path), - - GeodeCommands::Install { path } => package::install(&mut config, &path), + GeodeCommands::Install { path } => package::install(&mut config, &path), - GeodeCommands::Profile { commands } => profile::subcommand(&mut config, commands), + GeodeCommands::Profile { commands } => profile::subcommand(&mut config, commands), - GeodeCommands::Config { commands } => info::subcommand(&mut config, commands), + GeodeCommands::Config { commands } => info::subcommand(&mut config, commands), - GeodeCommands::Sdk { commands } => sdk::subcommand(&mut config, commands), + GeodeCommands::Sdk { commands } => sdk::subcommand(&mut config, commands), - GeodeCommands::Package { commands } => package::subcommand(&mut config, commands), - } + GeodeCommands::Package { commands } => package::subcommand(&mut config, commands), + } - config.save(); + config.save(); } diff --git a/src/package.rs b/src/package.rs index 1ec94d7..e38dac3 100644 --- a/src/package.rs +++ b/src/package.rs @@ -1,66 +1,66 @@ #![allow(unused_variables)] #![allow(unused_mut)] +use std::fs; use std::io::Read; use std::io::Write; use std::path::{Path, PathBuf}; -use std::fs; use clap::Subcommand; -use serde_json::{Value}; -use zip::ZipWriter; +use serde_json::Value; use zip::write::FileOptions; +use zip::ZipWriter; use crate::config::Config; +use crate::util::bmfont; use crate::util::cache::CacheBundle; use crate::util::mod_file::ModFileInfo; use crate::util::spritesheet; -use crate::util::bmfont; -use crate::{mod_file, cache}; -use crate::{fail, warn, info, done}; use crate::NiceUnwrap; +use crate::{cache, mod_file}; +use crate::{done, fail, info, warn}; #[derive(Subcommand, Debug)] #[clap(rename_all = "kebab-case")] pub enum Package { /// Install a .geode package to the current profile - Install { - /// Location of the .geode package to install - path: PathBuf - }, - - /// Create a .geode package - New { - /// Location of mod's folder - root_path: PathBuf, - - /// Add binary file - #[clap(short, long)] - binary: Vec, - - /// Location of output file - #[clap(short, long)] - output: PathBuf, - - /// Whether to install the generated package after creation - #[clap(short, long)] - install: bool - }, - - /// Fetch mod id from a package - GetId { - /// Location of package - input: PathBuf, - - /// Strip trailing newline - #[clap(long)] - raw: bool - }, + Install { + /// Location of the .geode package to install + path: PathBuf, + }, + + /// Create a .geode package + New { + /// Location of mod's folder + root_path: PathBuf, + + /// Add binary file + #[clap(short, long)] + binary: Vec, + + /// Location of output file + #[clap(short, long)] + output: PathBuf, + + /// Whether to install the generated package after creation + #[clap(short, long)] + install: bool, + }, + + /// Fetch mod id from a package + GetId { + /// Location of package + input: PathBuf, + + /// Strip trailing newline + #[clap(long)] + raw: bool, + }, /// Process the resources specified by a package Resources { - /// Location of mod's folder - root_path: PathBuf, + /// Location of mod's folder + root_path: PathBuf, /// Folder to place the created resources in output: PathBuf, @@ -72,18 +72,24 @@ pub enum Package { } pub fn install(config: &mut Config, pkg_path: &Path) { - let mod_path = config.get_profile(&config.current_profile) - .nice_unwrap("No current profile to install to!") - .borrow().gd_path - .join("geode") - .join("mods"); - - if !mod_path.exists() { - fs::create_dir_all(&mod_path).nice_unwrap("Could not setup mod installation"); - } - fs::copy(pkg_path, mod_path.join(pkg_path.file_name().unwrap())).nice_unwrap("Could not install mod"); - - done!("Installed {}", pkg_path.file_name().unwrap().to_str().unwrap()); + let mod_path = config + .get_profile(&config.current_profile) + .nice_unwrap("No current profile to install to!") + .borrow() + .gd_path + .join("geode") + .join("mods"); + + if !mod_path.exists() { + fs::create_dir_all(&mod_path).nice_unwrap("Could not setup mod installation"); + } + fs::copy(pkg_path, mod_path.join(pkg_path.file_name().unwrap())) + .nice_unwrap("Could not install mod"); + + done!( + "Installed {}", + pkg_path.file_name().unwrap().to_str().unwrap() + ); } fn zip_folder(path: &Path, output: &Path) { @@ -100,11 +106,17 @@ fn zip_folder(path: &Path, output: &Path) { // Only look at files if item.metadata().unwrap().is_file() { // Relativize - let mut relative_path = item.path().strip_prefix(path).unwrap().to_str().unwrap().to_string(); - + let mut relative_path = item + .path() + .strip_prefix(path) + .unwrap() + .to_str() + .unwrap() + .to_string(); + // Windows is weird and needs this change if cfg!(windows) { - relative_path = relative_path.replace('/', "\\"); + relative_path = relative_path.replace('/', "\\"); } zip_file.start_file(relative_path, zip_options).unwrap(); @@ -114,7 +126,15 @@ fn zip_folder(path: &Path, output: &Path) { zip_file.finish().nice_unwrap("Unable to zip"); - done!("Successfully packaged {}", output.file_name().unwrap().to_str().unwrap().bright_yellow()); + done!( + "Successfully packaged {}", + output + .file_name() + .unwrap() + .to_str() + .unwrap() + .bright_yellow() + ); } fn get_working_dir(id: &String) -> PathBuf { @@ -129,9 +149,9 @@ fn create_resources( mod_info: &ModFileInfo, mut cache_bundle: &mut Option, cache: &mut cache::ResourceCache, - working_dir: &PathBuf, + working_dir: &Path, output_dir: &PathBuf, - shut_up: bool + shut_up: bool, ) { // Make sure output directory exists fs::create_dir_all(output_dir).nice_unwrap("Could not create output directory"); @@ -139,17 +159,19 @@ fn create_resources( // Create spritesheets for sheet in mod_info.resources.spritesheets.values() { let sheet_file = spritesheet::get_spritesheet_bundles( - sheet, &output_dir, &mut cache_bundle, &mod_info, shut_up + sheet, + output_dir, + cache_bundle, + mod_info, + shut_up, ); - cache.add_sheet(sheet, sheet_file.cache_name(&working_dir)); + cache.add_sheet(sheet, sheet_file.cache_name(working_dir)); } // Create fonts for font in mod_info.resources.fonts.values() { - let font_file = bmfont::get_font_bundles( - font, &output_dir, &mut cache_bundle, mod_info, shut_up - ); - cache.add_font(font, font_file.cache_name(&working_dir)); + let font_file = bmfont::get_font_bundles(font, output_dir, cache_bundle, mod_info, shut_up); + cache.add_font(font, font_file.cache_name(working_dir)); } if !&mod_info.resources.sprites.is_empty() { @@ -171,7 +193,11 @@ fn create_resources( spritesheet::downscale(&mut sprite, 2); sprite.save(output_dir.join(base.to_string() + ".png")) - })().nice_unwrap(format!("Unable to copy sprite at {}", sprite_path.display())); + })() + .nice_unwrap(format!( + "Unable to copy sprite at {}", + sprite_path.display() + )); } if !&mod_info.resources.files.is_empty() { @@ -188,28 +214,32 @@ fn create_package_resources_only( config: &mut Config, root_path: &Path, output_dir: &PathBuf, - shut_up: bool + shut_up: bool, ) { // Parse mod.json let mod_json: Value = serde_json::from_str( - &fs::read_to_string(root_path.join("mod.json")).nice_unwrap("Could not read mod.json") - ).nice_unwrap("Could not parse mod.json"); + &fs::read_to_string(root_path.join("mod.json")).nice_unwrap("Could not read mod.json"), + ) + .nice_unwrap("Could not parse mod.json"); - let mod_info = mod_file::get_mod_file_info(&mod_json, &root_path); + let mod_info = mod_file::get_mod_file_info(&mod_json, root_path); // Setup cache - let mut cache_bundle = cache::get_cache_bundle_from_dir(&output_dir); + let mut cache_bundle = cache::get_cache_bundle_from_dir(output_dir); let mut new_cache = cache::ResourceCache::new(); create_resources( - config, &mod_info, - &mut cache_bundle, &mut new_cache, - &output_dir, output_dir, - shut_up + config, + &mod_info, + &mut cache_bundle, + &mut new_cache, + output_dir, + output_dir, + shut_up, ); - new_cache.save(&output_dir); - + new_cache.save(output_dir); + done!("Resources created at {}", output_dir.to_str().unwrap()); } @@ -218,13 +248,16 @@ fn create_package( root_path: &Path, binaries: Vec, mut output: PathBuf, - do_install: bool + do_install: bool, ) { // If it's a directory, add file path to it if output.is_dir() { output.push(root_path.file_name().unwrap()); output.set_extension("geode"); - warn!("Specified output is a directory. Creating package at {}", output.display()); + warn!( + "Specified output is a directory. Creating package at {}", + output.display() + ); } // Ensure at least one binary @@ -242,10 +275,11 @@ fn create_package( // Parse mod.json let mod_json: Value = serde_json::from_str( - &fs::read_to_string(root_path.join("mod.json")).nice_unwrap("Could not read mod.json") - ).nice_unwrap("Could not parse mod.json"); + &fs::read_to_string(root_path.join("mod.json")).nice_unwrap("Could not read mod.json"), + ) + .nice_unwrap("Could not parse mod.json"); - let mod_file_info = mod_file::get_mod_file_info(&mod_json, &root_path); + let mod_file_info = mod_file::get_mod_file_info(&mod_json, root_path); // Setup working directory let working_dir = get_working_dir(&mod_file_info.id); @@ -263,20 +297,25 @@ fn create_package( // Create resources create_resources( - config, &mod_file_info, - &mut cache_bundle, &mut new_cache, - &working_dir, &resource_dir, - false + config, + &mod_file_info, + &mut cache_bundle, + &mut new_cache, + &working_dir, + &resource_dir, + false, ); // Custom hardcoded resources let logo_png = root_path.join("logo.png"); if logo_png.exists() { - std::fs::copy(logo_png, working_dir.join("logo.png")).nice_unwrap("Could not copy logo.png"); + std::fs::copy(logo_png, working_dir.join("logo.png")) + .nice_unwrap("Could not copy logo.png"); } let about_md = root_path.join("about.md"); if about_md.exists() { - std::fs::copy(about_md, working_dir.join("about.md")).nice_unwrap("Could not copy about.md"); + std::fs::copy(about_md, working_dir.join("about.md")) + .nice_unwrap("Could not copy about.md"); } for binary in &binaries { @@ -299,18 +338,24 @@ fn get_id(input: PathBuf, raw: bool) { } else { let mut out = String::new(); - zip::ZipArchive::new(fs::File::open(input).unwrap()).nice_unwrap("Unable to unzip") - .by_name("mod.json").nice_unwrap("Unable to find mod.json in package") - .read_to_string(&mut out).nice_unwrap("Unable to read mod.json"); + zip::ZipArchive::new(fs::File::open(input).unwrap()) + .nice_unwrap("Unable to unzip") + .by_name("mod.json") + .nice_unwrap("Unable to find mod.json in package") + .read_to_string(&mut out) + .nice_unwrap("Unable to read mod.json"); out }; - let json = serde_json::from_str::(&text).nice_unwrap("Unable to parse mod.json"); + let json = + serde_json::from_str::(&text).nice_unwrap("Unable to parse mod.json"); let id = json - .get("id").nice_unwrap("[mod.json]: Missing key 'id'") - .as_str().nice_unwrap("[mod.json].id: Expected string"); + .get("id") + .nice_unwrap("[mod.json]: Missing key 'id'") + .as_str() + .nice_unwrap("[mod.json].id: Expected string"); if raw { print!("{}", id); @@ -323,10 +368,19 @@ pub fn subcommand(config: &mut Config, cmd: Package) { match cmd { Package::Install { path } => install(config, &path), - Package::New { root_path, binary: binaries, output, install } => create_package(config, &root_path, binaries, output, install), - + Package::New { + root_path, + binary: binaries, + output, + install, + } => create_package(config, &root_path, binaries, output, install), + Package::GetId { input, raw } => get_id(input, raw), - Package::Resources { root_path, output, shut_up } => create_package_resources_only(config, &root_path, &output, shut_up), + Package::Resources { + root_path, + output, + shut_up, + } => create_package_resources_only(config, &root_path, &output, shut_up), } } diff --git a/src/profile.rs b/src/profile.rs index b9ae6f2..124a1c5 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -1,3 +1,8 @@ +use crate::config::{Config, Profile as CfgProfile}; +use crate::{done, fail}; +use clap::Subcommand; +use colored::Colorize; +use std::cell::RefCell; /** * geode profile list: List profiles of geode * geode profile switch: Switch main geode profile @@ -5,14 +10,8 @@ * geode profile remove: Remove geode profile from the index * geode profile rename: Rename geode profile */ - use std::path::Path; -use std::cell::RefCell; -use clap::Subcommand; -use colored::Colorize; use std::path::PathBuf; -use crate::config::{Config, Profile as CfgProfile}; -use crate::{done, fail}; #[derive(Subcommand, Debug)] pub enum Profile { @@ -22,24 +21,23 @@ pub enum Profile { /// Switch main profile Switch { /// New main profile - profile: String + profile: String, }, /// Add profile Add { /// New profile location location: PathBuf, - + /// New profile name #[clap(short, long)] name: String, - }, /// Remove profile Remove { /// Profile to remove - name: String + name: String, }, /// Rename profile @@ -48,13 +46,13 @@ pub enum Profile { old: String, /// New name - new: String - } + new: String, + }, } fn is_valid_geode_dir(_dir: &Path) -> bool { //TODO: this - return true; + true } pub fn subcommand(config: &mut Config, cmd: Profile) { @@ -64,9 +62,13 @@ pub fn subcommand(config: &mut Config, cmd: Profile) { let name = &profile.borrow().name; let path = &profile.borrow().gd_path; - println!("{} [ path = {} ]", name.bright_cyan(), path.to_string_lossy().bright_green()); + println!( + "{} [ path = {} ]", + name.bright_cyan(), + path.to_string_lossy().bright_green() + ); } - }, + } Profile::Switch { profile } => { if config.get_profile(&Some(profile.to_owned())).is_none() { @@ -77,7 +79,7 @@ pub fn subcommand(config: &mut Config, cmd: Profile) { done!("'{}' is now the current profile", &profile); config.current_profile = Some(profile); } - }, + } Profile::Add { name, location } => { if config.get_profile(&Some(name.to_owned())).is_some() { @@ -86,9 +88,11 @@ pub fn subcommand(config: &mut Config, cmd: Profile) { fail!("The specified path does not point to a valid Geode installation"); } else { done!("A new profile named '{}' has been created", &name); - config.profiles.push(RefCell::new(CfgProfile::new(name, location))); + config + .profiles + .push(RefCell::new(CfgProfile::new(name, location))); } - }, + } Profile::Remove { name } => { if config.get_profile(&Some(name.to_owned())).is_none() { @@ -97,10 +101,10 @@ pub fn subcommand(config: &mut Config, cmd: Profile) { config.profiles.retain(|x| x.borrow().name != name); done!("'{}' has been removed", name); } - }, + } Profile::Rename { old, new } => { config.rename_profile(&old, new); } } -} \ No newline at end of file +} diff --git a/src/sdk.rs b/src/sdk.rs index 5de17d6..7e351aa 100644 --- a/src/sdk.rs +++ b/src/sdk.rs @@ -1,17 +1,17 @@ -use std::io::{stdout, stdin, Write}; -use std::path::{PathBuf, Path}; use crate::config::Config; use clap::Subcommand; +use colored::Colorize; use git2::build::RepoBuilder; use git2::{FetchOptions, RemoteCallbacks, Repository}; -use colored::Colorize; -use serde::{Deserialize}; -use std::fs; +use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT}; use semver::Version; -use reqwest::header::{HeaderMap, USER_AGENT, HeaderValue}; +use serde::Deserialize; +use std::fs; +use std::io::{stdin, stdout, Write}; +use std::path::PathBuf; -use crate::{fail, warn, info, done, fatal}; use crate::NiceUnwrap; +use crate::{done, fail, fatal, info, warn}; #[derive(Deserialize)] struct GithubReleaseAsset { @@ -30,7 +30,10 @@ pub enum Branch { Stable, } -fn download_url(url: String, file_name: &PathBuf) -> Result<(), Box> { +fn download_url( + url: String, + file_name: &PathBuf, +) -> Result<(), Box> { let res = reqwest::blocking::get(url)?; let mut file = fs::File::create(file_name)?; let mut content = std::io::Cursor::new(res.bytes()?); @@ -47,7 +50,7 @@ pub enum Sdk { reinstall: bool, /// Path to install - path: Option + path: Option, }, /// Install prebuilt binaries for SDK @@ -68,7 +71,7 @@ pub enum Sdk { } fn parse_version(str: &str) -> Result { - if str.starts_with("v") { + if str.starts_with('v') { Version::parse(&str[1..]) } else { Version::parse(str) @@ -88,7 +91,7 @@ fn uninstall(config: &mut Config) -> bool { ans = ans.trim().to_string(); if ans != "Yes" { fail!("Aborting"); - return false; + return false; } if let Err(e) = std::fs::remove_dir_all(sdk_path) { @@ -97,11 +100,10 @@ fn uninstall(config: &mut Config) -> bool { } done!("Uninstalled Geode SDK"); - return true; + true } fn install(config: &mut Config, path: PathBuf) { - let parent = path.parent().unwrap(); if std::env::var("GEODE_SDK").is_ok() { @@ -116,7 +118,11 @@ fn install(config: &mut Config, path: PathBuf) { let mut callbacks = RemoteCallbacks::new(); callbacks.sideband_progress(|x| { - print!("{} {}", "| Info |".bright_cyan(), std::str::from_utf8(x).unwrap()); + print!( + "{} {}", + "| Info |".bright_cyan(), + std::str::from_utf8(x).unwrap() + ); true }); @@ -126,12 +132,16 @@ fn install(config: &mut Config, path: PathBuf) { let mut builder = RepoBuilder::new(); builder.fetch_options(fetch); - let repo = builder.clone("https://github.com/geode-sdk/geode", &path) + let repo = builder + .clone("https://github.com/geode-sdk/geode", &path) .nice_unwrap("Could not download SDK"); // TODO: set GEODE_SDK enviroment var - info!("Please set the GEODE_SDK enviroment variable to {}", path.to_str().unwrap()); + info!( + "Please set the GEODE_SDK enviroment variable to {}", + path.to_str().unwrap() + ); switch_to_tag(config, &repo); @@ -146,37 +156,42 @@ fn update(config: &mut Config, branch: Option) { Some(Branch::Nightly) => { info!("Switching to nightly"); config.sdk_nightly = true; - }, + } Some(Branch::Stable) => { info!("Switching to stable"); config.sdk_nightly = false; - }, - None => {}, + } + None => {} }; info!("Updating SDK"); - + // Initialize repository - let repo = Repository::open( - Config::sdk_path() - ).nice_unwrap("Could not initialize local SDK repository"); + let repo = Repository::open(Config::sdk_path()) + .nice_unwrap("Could not initialize local SDK repository"); // Fetch - let mut remote = repo.find_remote( - repo.remotes().unwrap().iter().next().unwrap().unwrap() - ).unwrap(); + let mut remote = repo + .find_remote(repo.remotes().unwrap().iter().next().unwrap().unwrap()) + .unwrap(); let mut callbacks = RemoteCallbacks::new(); callbacks.sideband_progress(|x| { - print!("{} {}", "| Info |".bright_cyan(), std::str::from_utf8(x).unwrap()); + print!( + "{} {}", + "| Info |".bright_cyan(), + std::str::from_utf8(x).unwrap() + ); true }); - remote.fetch( - &["main"], - Some(FetchOptions::new().remote_callbacks(callbacks)), - None - ).nice_unwrap("Could not fetch latest update"); + remote + .fetch( + &["main"], + Some(FetchOptions::new().remote_callbacks(callbacks)), + None, + ) + .nice_unwrap("Could not fetch latest update"); // Check if can fast-forward let fetch_head = repo.find_reference("FETCH_HEAD").unwrap(); @@ -190,7 +205,8 @@ fn update(config: &mut Config, branch: Option) { done!("SDK is up to date"); } else if !merge_analysis.is_fast_forward() { fail!("Cannot update SDK, it has local changes"); - info!("Go into the repository at {} and manually run `git pull`", + info!( + "Go into the repository at {} and manually run `git pull`", Config::sdk_path().to_str().unwrap() ); } else { @@ -211,20 +227,22 @@ fn switch_to_tag(config: &mut Config, repo: &Repository) { repo.set_head("refs/heads/main").unwrap(); let mut refer = repo.find_reference("refs/heads/main").unwrap(); refer.set_target(fetch_commit.id(), "Fast-Forward").unwrap(); - repo.checkout_head(None).nice_unwrap("Unable to switch to latest commit"); + repo.checkout_head(None) + .nice_unwrap("Unable to switch to latest commit"); info!("Switched to latest commit"); return; } let mut latest_version: Option = None; - for tag in repo.tag_names(None).nice_unwrap("Unable to get SDK tags").iter() { - if let Some(tag) = tag { - if let Ok(version) = parse_version(tag) { - if latest_version.as_ref().is_none() { - latest_version = Some(version); - } else if version > latest_version.as_ref().unwrap().to_owned() { - latest_version = Some(version); - } + for tag in repo + .tag_names(None) + .nice_unwrap("Unable to get SDK tags") + .iter() + .flatten() + { + if let Ok(version) = parse_version(tag) { + if latest_version.as_ref().is_none() || &version > latest_version.as_ref().unwrap() { + latest_version = Some(version); } } } @@ -256,17 +274,22 @@ fn install_binaries(config: &mut Config) { release_tag = format!("v{}", ver); target_dir = Config::sdk_path().join(format!("bin/{}", ver)); } - let url = format!("https://api.github.com/repos/geode-sdk/geode/releases/tags/{}", release_tag); + let url = format!( + "https://api.github.com/repos/geode-sdk/geode/releases/tags/{}", + release_tag + ); let mut headers = HeaderMap::new(); headers.insert(USER_AGENT, HeaderValue::from_static("github_api/1.0")); let res = reqwest::blocking::Client::new() - .get(&url).headers(headers).send() + .get(&url) + .headers(headers) + .send() .nice_unwrap("Unable to get download info from GitHub") .json::() .nice_unwrap("Unable to parse GitHub response"); - + let mut target_url: Option = None; for asset in res.assets { #[cfg(target_os = "windows")] @@ -297,8 +320,9 @@ fn install_binaries(config: &mut Config) { let file = fs::File::open(&temp_zip).nice_unwrap("Unable to read downloaded ZIP"); let mut zip = zip::ZipArchive::new(file).nice_unwrap("Downloaded ZIP appears to be corrupted"); - zip.extract(target_dir).nice_unwrap("Unable to unzip downloaded binaries"); - + zip.extract(target_dir) + .nice_unwrap("Unable to unzip downloaded binaries"); + fs::remove_file(temp_zip).nice_unwrap("Unable to clean up downloaded ZIP"); done!("Binaries installed"); @@ -306,32 +330,37 @@ fn install_binaries(config: &mut Config) { pub fn get_version() -> Version { Version::parse( - fs::read_to_string( - Config::sdk_path().join("VERSION") - ).nice_unwrap("Unable to read SDK version, make sure you are using SDK v0.4.2 or later").as_str() - ).nice_unwrap("Invalid SDK version") + fs::read_to_string(Config::sdk_path().join("VERSION")) + .nice_unwrap("Unable to read SDK version, make sure you are using SDK v0.4.2 or later") + .as_str(), + ) + .nice_unwrap("Invalid SDK version") } pub fn subcommand(config: &mut Config, cmd: Sdk) { match cmd { Sdk::Install { reinstall, path } => { - if reinstall { - if !uninstall(config) { - return; - } + if reinstall && !uninstall(config) { + return; } - install(config, path.unwrap_or(if cfg!(target_os = "macos") { - PathBuf::from("/Users/Shared/Geode/sdk") - } else { - dirs::document_dir() - .nice_unwrap( - "No default path available! \ - Please provide a path manually" - ).join("Geode") - })); - }, - Sdk::Uninstall => { uninstall(config); }, + install( + config, + path.unwrap_or(if cfg!(target_os = "macos") { + PathBuf::from("/Users/Shared/Geode/sdk") + } else { + dirs::document_dir() + .nice_unwrap( + "No default path available! \ + Please provide a path manually", + ) + .join("Geode") + }), + ); + } + Sdk::Uninstall => { + uninstall(config); + } Sdk::Update { branch } => update(config, branch), Sdk::Version => info!("Geode SDK version: {}", get_version()), Sdk::InstallBinaries => install_binaries(config), diff --git a/src/template.rs b/src/template.rs index 7bc2e7b..974c75a 100644 --- a/src/template.rs +++ b/src/template.rs @@ -1,67 +1,71 @@ +use crate::config::Config; +use crate::sdk::get_version; +use crate::{done, fail, fatal, info, warn}; use git2::Repository; -use std::io::{stdin, stdout, Write}; -use std::path::PathBuf; -use std::fs; -use rustyline::Editor; use path_absolutize::Absolutize; -use serde_json::json; +use rustyline::Editor; use serde::Serialize; -use crate::{fail, fatal, warn, info, done}; -use crate::config::Config; -use crate::sdk::get_version; +use serde_json::json; +use std::fs; +use std::io::{stdin, stdout, Write}; +use std::path::PathBuf; fn create_template( - config: &mut Config, - project_location: PathBuf, - name: String, - version: String, - id: String, - developer: String, - description: String + config: &mut Config, + project_location: PathBuf, + name: String, + version: String, + id: String, + developer: String, + description: String, ) { - - if project_location.exists() { - warn!("The provided location already exists."); - print!(" Are you sure you want to proceed? (y/N) "); - - stdout().flush().unwrap(); - - let mut ans = String::new(); - stdin().read_line(&mut ans).unwrap(); - ans = ans.trim().to_string(); - if !(ans == "y" || ans == "Y") { - info!("Aborting"); - return; - } - } else { - fs::create_dir_all(&project_location) - .unwrap_or_else(|e| fatal!("Unable to create project directory: {}", e)); - } + if project_location.exists() { + warn!("The provided location already exists."); + print!(" Are you sure you want to proceed? (y/N) "); + + stdout().flush().unwrap(); + + let mut ans = String::new(); + stdin().read_line(&mut ans).unwrap(); + ans = ans.trim().to_string(); + if !(ans == "y" || ans == "Y") { + info!("Aborting"); + return; + } + } else { + fs::create_dir_all(&project_location) + .unwrap_or_else(|e| fatal!("Unable to create project directory: {}", e)); + } // Clone repository - Repository::clone("https://github.com/geode-sdk/example-mod", &project_location) - .unwrap_or_else(|e| fatal!("Unable to clone repository: {}", e)); + Repository::clone( + "https://github.com/geode-sdk/example-mod", + &project_location, + ) + .unwrap_or_else(|e| fatal!("Unable to clone repository: {}", e)); fs::remove_dir_all(project_location.join(".git")).unwrap(); // Replace "Template" with project name (no spaces) let filtered_name: String = name.chars().filter(|c| !c.is_whitespace()).collect(); - for file in vec!["README.md", "CMakeLists.txt"] { - let file = project_location.join(file); - - let contents = fs::read_to_string(&file).unwrap().replace("Template", &filtered_name); - fs::write(file, contents).unwrap(); - } + for file in &["README.md", "CMakeLists.txt"] { + let file = project_location.join(file); + + let contents = fs::read_to_string(&file) + .unwrap() + .replace("Template", &filtered_name); + fs::write(file, contents).unwrap(); + } // Default mod.json let mod_json = json!({ - "geode": get_version().to_string(), - "version": version, - "id": id, - "name": name, - "developer": developer, - "description": description + "geode": get_version().to_string(), + "version": version, + "id": id, + "name": name, + "developer": developer, + "description": description }); // Format neatly @@ -72,71 +76,76 @@ fn create_template( // Write formatted json fs::write( - &project_location.join("mod.json"), - String::from_utf8(ser.into_inner()).unwrap() - ).unwrap_or_else(|e| fatal!("Unable to write to project: {}", e)); + &project_location.join("mod.json"), + String::from_utf8(ser.into_inner()).unwrap(), + ) + .unwrap_or_else(|e| fatal!("Unable to write to project: {}", e)); done!("Succesfully initialized project! Happy modding :)"); } - // fix this fn ask_value(prompt: &str, default: Option<&str>, required: bool) -> String { - let text = format!("{}{}: ", prompt, if required { "" } else { " (optional)" }); - let mut line_reader = Editor::<()>::new(); - loop { - let line = line_reader.readline_with_initial(&text, (default.unwrap_or(""), "")).unwrap(); - line_reader.add_history_entry(&line); - - if line.is_empty() { - if required { - fail!("Please enter a value"); - } else { - return default.unwrap_or("").to_string(); - } - } else { - return line.trim().to_string(); - } - } + let text = format!("{}{}: ", prompt, if required { "" } else { " (optional)" }); + let mut line_reader = Editor::<()>::new(); + loop { + let line = line_reader + .readline_with_initial(&text, (default.unwrap_or(""), "")) + .unwrap(); + line_reader.add_history_entry(&line); + + if line.is_empty() { + if required { + fail!("Please enter a value"); + } else { + return default.unwrap_or("").to_string(); + } + } else { + return line.trim().to_string(); + } + } } pub fn build_template(config: &mut Config, name: Option, location: Option) { let final_name = ask_value("Name", name.as_deref(), true); - let location = location.unwrap_or(std::env::current_dir().unwrap().join(&final_name)); + let location = location.unwrap_or_else(|| std::env::current_dir().unwrap().join(&final_name)); let location = location.absolutize().unwrap(); - let final_version = ask_value("Version", Some("v1.0.0"), true); - - let final_developer = ask_value( - "Developer", - config.default_developer.as_ref().map(|x| &**x), - true - ); - - if config.default_developer.is_none() { - info!("Using '{}' as the default developer for all future projects.", &final_developer); - config.default_developer = Some(final_developer.clone()); - } - - let final_description = ask_value("Description", None, false); - let final_location = PathBuf::from(ask_value("Location", Some(&location.to_string_lossy()), true)); - - let mod_id = format!( - "{}.{}", - final_developer.to_lowercase().replace(' ', "_"), - final_name.to_lowercase().replace(' ', "_") - ); - - info!("Creating project {}", mod_id); - - create_template( - config, - final_location, - final_name, - final_version, - mod_id, - final_developer, - final_description - ); + let final_version = ask_value("Version", Some("v1.0.0"), true); + + let final_developer = ask_value("Developer", config.default_developer.as_deref(), true); + + if config.default_developer.is_none() { + info!( + "Using '{}' as the default developer for all future projects.", + &final_developer + ); + config.default_developer = Some(final_developer.clone()); + } + + let final_description = ask_value("Description", None, false); + let final_location = PathBuf::from(ask_value( + "Location", + Some(&location.to_string_lossy()), + true, + )); + + let mod_id = format!( + "{}.{}", + final_developer.to_lowercase().replace(' ', "_"), + final_name.to_lowercase().replace(' ', "_") + ); + + info!("Creating project {}", mod_id); + + create_template( + config, + final_location, + final_name, + final_version, + mod_id, + final_developer, + final_description, + ); } diff --git a/src/util/bmfont.rs b/src/util/bmfont.rs index 19e5e78..c1f82dd 100644 --- a/src/util/bmfont.rs +++ b/src/util/bmfont.rs @@ -1,24 +1,22 @@ use crate::cache::CacheBundle; use crate::mod_file::BitmapFont; use std::fs; -use std::io::Read; use std::path::Path; use std::path::PathBuf; use texture_packer::exporter::ImageExporter; +use texture_packer::texture::Texture; use texture_packer::TexturePacker; use texture_packer::TexturePackerConfig; -use texture_packer::texture::Texture; -use crate::{done, info, fatal, NiceUnwrap}; -use image::{Rgba, Rgb, RgbaImage, LumaA, EncodableLayout, Pixel, GenericImageView, DynamicImage, GrayAlphaImage}; -use signed_distance_field::prelude::*; +use crate::{done, fatal, info, NiceUnwrap}; +use image::{Rgba, RgbaImage}; use super::mod_file::ModFileInfo; use super::spritesheet::downscale; struct RenderedChar { id: char, - img: RgbaImage + img: RgbaImage, } /*fn smoothstep(start: f32, end: f32, x: f32) -> f32 { @@ -63,7 +61,7 @@ fn gen_outline(sdf: SignedDistanceField, size: f32) -> im let x = x as u32; let y = y as u32; - let value = + let value = smoothstep(0.0 - size - ramp, 0.0 - size, dist) - smoothstep(0.0 + size, 0.0 + size + ramp, dist); // let value = smoothstep(-10.0, 10.0, dist); @@ -76,7 +74,7 @@ fn gen_outline(sdf: SignedDistanceField, size: f32) -> im }*/ fn generate_char(font: &BitmapFont, metrics: fontdue::Metrics, data: Vec) -> Option { - if data.len() == 0 { + if data.is_empty() { return None; } @@ -93,7 +91,7 @@ fn generate_char(font: &BitmapFont, metrics: fontdue::Metrics, data: Vec) -> let mut input_buf = GrayAlphaImage::new(width + font.outline, height + font.outline); image::imageops::overlay(&mut input_buf, &tmp_char, font.outline as i64/ 2, font.outline as i64/ 2); - + let outline = gen_outline(gen_sdf(&DynamicImage::ImageLumaA8(input_buf.clone())), font.outline as f32); image::imageops::overlay(&mut input_buf, &outline, 0, 0); @@ -102,70 +100,72 @@ fn generate_char(font: &BitmapFont, metrics: fontdue::Metrics, data: Vec) -> let width = metrics.width as u32; let height = metrics.height as u32; - Some(RgbaImage::from_fn( - width, - height, - |x, y| { - Rgba::([255, 255, 255, data[(x + width*y) as usize]]) - } - )) + Some(RgbaImage::from_fn(width, height, |x, y| { + Rgba::([255, 255, 255, data[(x + width * y) as usize]]) + })) } fn initialize_font_bundle( bundle: &FontBundle, font: &BitmapFont, factor: u32, - _mod_info: &ModFileInfo + _mod_info: &ModFileInfo, ) -> PathBuf { // Get all characters from the charset format - let chars: Vec = font.charset + let chars: Vec = font + .charset .as_deref() .unwrap_or("32-126,8226") .split(',') - .map(|x| x.split('-').map(|x| x.parse().unwrap()).collect::>()) .map(|x| { + x.split('-') + .map(|x| x.parse().unwrap()) + .collect::>() + }) + .flat_map(|x| { if x.len() <= 2 { - *x.first().unwrap() .. *x.last().unwrap() + 1 + *x.first().unwrap()..*x.last().unwrap() + 1 } else { fatal!("Invalid charset '{}'", font.charset.as_ref().unwrap()); } }) - .flatten() .map(|c| char::from_u32(c).unwrap()) .collect(); // Read & parse source .ttf file let ttf_font = fontdue::Font::from_bytes( fs::read(&font.path).unwrap(), - fontdue::FontSettings::default() - ).unwrap(); + fontdue::FontSettings::default(), + ) + .unwrap(); // Rasterize characters from charset using the source font - let rasterized_chars: Vec<_> = chars.iter().filter_map(|c| { - let (metrics, data) = ttf_font.rasterize(*c, font.size as f32); - - if let Some(mut img) = generate_char(font, metrics, data) { - downscale(&mut img, factor); - Some(RenderedChar { - id: *c, - img - }) - } else { - None - } - }).collect(); + let rasterized_chars: Vec<_> = chars + .iter() + .filter_map(|c| { + let (metrics, data) = ttf_font.rasterize(*c, font.size as f32); + + if let Some(mut img) = generate_char(font, metrics, data) { + downscale(&mut img, factor); + Some(RenderedChar { id: *c, img }) + } else { + None + } + }) + .collect(); // Determine bounds to create the most efficient packing let char_widths = rasterized_chars.iter().map(|c| c.img.width()); let widest_char: u32 = char_widths.clone().max().unwrap(); let width_sum: u32 = char_widths.sum(); - let mean_height: f64 = (rasterized_chars.iter().map(|c| c.img.height()).sum::() as f64) / rasterized_chars.len() as f64; + let mean_height: f64 = (rasterized_chars.iter().map(|c| c.img.height()).sum::() as f64) + / rasterized_chars.len() as f64; let mut max_width = (width_sum as f64 * mean_height).sqrt() as u32; if max_width < widest_char { - max_width = widest_char + 2; + max_width = widest_char + 2; } // Configuration for texture packer @@ -179,8 +179,10 @@ fn initialize_font_bundle( ..Default::default() }; let mut packer = TexturePacker::new_skyline(config); - - rasterized_chars.iter().for_each(|x| packer.pack_ref(x.id, &x.img).unwrap()); + + rasterized_chars + .iter() + .for_each(|x| packer.pack_ref(x.id, &x.img).unwrap()); // Create .png file let exporter = ImageExporter::export(&packer).unwrap(); @@ -189,12 +191,12 @@ fn initialize_font_bundle( // Get all characters and their metrics (positions in the png) // Add space explicitly because it's empty and not in the frames - // todo: figure out why space isn't there and how to make sure + // todo: figure out why space isn't there and how to make sure // other space characters don't get omitted - let mut all_chars = vec!(format!( + let mut all_chars = vec![format!( "char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=0 xadvance={} page=0 chln=0", ttf_font.metrics(' ', font.size as f32).advance_width - )); + )]; for (name, frame) in packer.get_frames() { let metrics = ttf_font.metrics(*name, font.size as f32); all_chars.push(format!( @@ -209,27 +211,32 @@ fn initialize_font_bundle( metrics.advance_width as i32 )); } - // Make sure all packings for the same input produce identical output by + // Make sure all packings for the same input produce identical output by // sorting all_chars.sort(); // Get all kerning pairs - let mut all_kerning_pairs = rasterized_chars.iter().flat_map( - |left| rasterized_chars.iter().filter_map(|right| { - ttf_font.horizontal_kern( - left.id, right.id, font.size as f32 - ).map(|kern| format!( - "kerning first={} second={} amount={}", - left.id, right.id, kern as i32 - )) + let mut all_kerning_pairs = rasterized_chars + .iter() + .flat_map(|left| { + rasterized_chars.iter().filter_map(|right| { + ttf_font + .horizontal_kern(left.id, right.id, font.size as f32) + .map(|kern| { + format!( + "kerning first={} second={} amount={}", + left.id, right.id, kern as i32 + ) + }) + }) }) - ).collect::>(); - // Make sure all packings for the same input produce identical output by + .collect::>(); + // Make sure all packings for the same input produce identical output by // sorting all_kerning_pairs.sort(); // Create .fnt file - let line_metrics = ttf_font.horizontal_line_metrics(font.size as f32).unwrap(); + let line_metrics = ttf_font.horizontal_line_metrics(font.size as f32).unwrap(); let fnt_data = format!( "info face=\"{font_name}\" size={font_size} bold=0 italic=0 \ charset=\"\" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1\n\ @@ -259,13 +266,13 @@ fn initialize_font_bundle( pub struct FontBundle { pub png: PathBuf, - pub fnt: PathBuf + pub fnt: PathBuf, } pub struct FontBundles { pub sd: FontBundle, pub hd: FontBundle, - pub uhd: FontBundle + pub uhd: FontBundle, } impl FontBundles { @@ -273,10 +280,7 @@ impl FontBundles { let mut fnt = base.to_owned(); fnt.set_extension("fnt"); - FontBundle { - png: base, - fnt - } + FontBundle { png: base, fnt } } pub fn new(mut base: PathBuf) -> FontBundles { @@ -290,7 +294,7 @@ impl FontBundles { FontBundles { sd: FontBundles::new_file(base), hd: FontBundles::new_file(hd), - uhd: FontBundles::new_file(uhd) + uhd: FontBundles::new_file(uhd), } } @@ -314,8 +318,8 @@ fn extract_from_cache( info!("Extracting '{}' from cache", path_name); } cache_bundle.extract_cached_into( - path_name, - &working_dir.join(path.file_name().unwrap().to_str().unwrap()) + path_name, + &working_dir.join(path.file_name().unwrap().to_str().unwrap()), ); } @@ -324,7 +328,7 @@ pub fn get_font_bundles( working_dir: &Path, cache: &mut Option, mod_info: &ModFileInfo, - shut_up: bool + shut_up: bool, ) -> FontBundles { // todo: we really should add a global verbosity option and logging levels for that @@ -352,22 +356,22 @@ pub fn get_font_bundles( return bundles; } } - + if !shut_up { info!("Font is not cached, building from scratch"); } - let mut bundles = FontBundles::new(working_dir.join(font.name.to_string() + ".png")); + let bundles = FontBundles::new(working_dir.join(font.name.to_string() + ".png")); // Create new font info!("Creating normal font"); - initialize_font_bundle(&mut bundles.sd, font, 4, mod_info); + initialize_font_bundle(&bundles.sd, font, 4, mod_info); info!("Creating HD font"); - initialize_font_bundle(&mut bundles.hd, font, 2, mod_info); + initialize_font_bundle(&bundles.hd, font, 2, mod_info); info!("Creating UHD font"); - initialize_font_bundle(&mut bundles.uhd, font, 1, mod_info); + initialize_font_bundle(&bundles.uhd, font, 1, mod_info); done!("Built font {}", font.name.bright_yellow()); bundles diff --git a/src/util/cache.rs b/src/util/cache.rs index 35c3b9f..0e52e21 100644 --- a/src/util/cache.rs +++ b/src/util/cache.rs @@ -1,9 +1,9 @@ +use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use std::io::Read; -use std::fs::File; use std::fs; +use std::fs::File; +use std::io::Read; use std::path::{Path, PathBuf}; -use serde::{Deserialize, Serialize}; use crate::mod_file::BitmapFont; use crate::spritesheet::SpriteSheet; @@ -13,7 +13,7 @@ use crate::NiceUnwrap; #[derive(Serialize, Deserialize)] pub struct ResourceCache { pub spritesheets: HashMap, - pub fonts: HashMap + pub fonts: HashMap, } pub struct CacheBundle { @@ -32,14 +32,14 @@ impl CacheBundle { cached_file.read_to_end(&mut buf).unwrap(); // Write buffer into output directory, same file name - std::fs::write(&output, buf).unwrap(); - }, + std::fs::write(output, buf).unwrap(); + } CacheBundleSource::Directory(dir) => { if dir.join(name) != *output { std::fs::copy(dir.join(name), output).unwrap(); } - }, + } } } } @@ -50,80 +50,97 @@ pub enum CacheBundleSource { } fn hash_sheet(sheet: &SpriteSheet) -> String { - let mut hashes: Vec = sheet.files.iter().map(|x| sha256::digest_file(x).unwrap()).collect(); + let mut hashes: Vec = sheet + .files + .iter() + .map(|x| sha256::digest_file(x).unwrap()) + .collect(); hashes.sort(); sha256::digest(hashes.into_iter().collect::()) } fn hash_font(font: &BitmapFont) -> String { - sha256::digest(format!("{}|{}|{}|{}", + sha256::digest(format!( + "{}|{}|{}|{}", font.size, font.outline, - font.charset.clone().unwrap_or(String::new()), + font.charset.clone().unwrap_or_default(), sha256::digest_file(font.path.clone()).unwrap() )) } pub fn get_cache_bundle_from_dir(path: &Path) -> Option { - path.join(".geode_cache").exists().then(|| { - let cache = ResourceCache::load( - fs::read_to_string(path.join(".geode_cache")).nice_unwrap("Unable to read cache") - ); - Some(CacheBundle { - cache, - src: CacheBundleSource::Directory(path.to_path_buf()) + path.join(".geode_cache") + .exists() + .then(|| { + let cache = ResourceCache::load( + fs::read_to_string(path.join(".geode_cache")).nice_unwrap("Unable to read cache"), + ); + Some(CacheBundle { + cache, + src: CacheBundleSource::Directory(path.to_path_buf()), + }) }) - }).flatten() + .flatten() } pub fn get_cache_bundle(path: &Path) -> Option { - path.exists().then(|| { - match zip::ZipArchive::new(File::open(path).nice_unwrap("Unable to open cache file")) { - Ok(mut archive) => { - let cache: ResourceCache; - - if archive.by_name(".geode_cache").is_ok() { - let mut cache_data = String::new(); - if archive.by_name(".geode_cache").unwrap().read_to_string(&mut cache_data).is_err() { - return None; + path.exists() + .then(|| { + match zip::ZipArchive::new(File::open(path).nice_unwrap("Unable to open cache file")) { + Ok(mut archive) => { + let cache: ResourceCache; + + if archive.by_name(".geode_cache").is_ok() { + let mut cache_data = String::new(); + if archive + .by_name(".geode_cache") + .unwrap() + .read_to_string(&mut cache_data) + .is_err() + { + return None; + } + + cache = ResourceCache::load(cache_data); + } else { + cache = ResourceCache::new(); } - cache = ResourceCache::load(cache_data); - } else { - cache = ResourceCache::new(); + Some(CacheBundle { + cache, + src: CacheBundleSource::Archive(archive), + }) } - Some(CacheBundle { - cache, - src: CacheBundleSource::Archive(archive) - }) - }, - - Err(e) => { - warn!("Error reading cache from previous build: {}. Disabling cache for this build", e); - None + Err(e) => { + warn!("Error reading cache from previous build: {}. Disabling cache for this build", e); + None + } } - } - }).flatten() + }) + .flatten() } impl ResourceCache { pub fn new() -> ResourceCache { ResourceCache { spritesheets: HashMap::new(), - fonts: HashMap::new() + fonts: HashMap::new(), } } pub fn load(cache_data: String) -> ResourceCache { - serde_json::from_str::(&cache_data).nice_unwrap("Unable to parse cache file: {}") + serde_json::from_str::(&cache_data) + .nice_unwrap("Unable to parse cache file: {}") } pub fn save(&self, path: &Path) { std::fs::write( path.join(".geode_cache"), - serde_json::to_string(self).unwrap() - ).unwrap() + serde_json::to_string(self).unwrap(), + ) + .unwrap() } pub fn add_sheet(&mut self, sheet: &SpriteSheet, path: PathBuf) { @@ -141,10 +158,10 @@ impl ResourceCache { } pub fn fetch_spritesheet_bundles(&self, sheet: &SpriteSheet) -> Option<&Path> { - self.spritesheets.get(&hash_sheet(sheet)).and_then(|x| Some(&**x)) + self.spritesheets.get(&hash_sheet(sheet)).map(|x| &**x) } pub fn fetch_font_bundles(&self, font: &BitmapFont) -> Option<&Path> { - self.fonts.get(&hash_font(font)).and_then(|x| Some(&**x)) + self.fonts.get(&hash_font(font)).map(|x| &**x) } } diff --git a/src/util/config.rs b/src/util/config.rs index 818d8ee..26d698a 100644 --- a/src/util/config.rs +++ b/src/util/config.rs @@ -5,8 +5,8 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use std::path::PathBuf; -use crate::{fail, warn, done, info, fatal}; use crate::NiceUnwrap; +use crate::{done, fail, fatal, info, warn}; #[derive(Serialize, Deserialize, Clone)] #[serde(rename_all = "kebab-case")] @@ -14,8 +14,8 @@ pub struct Profile { pub name: String, pub gd_path: PathBuf, - #[serde(flatten)] - other: HashMap + #[serde(flatten)] + other: HashMap, } #[derive(Serialize, Deserialize, Clone)] @@ -25,8 +25,8 @@ pub struct Config { pub profiles: Vec>, pub default_developer: Option, pub sdk_nightly: bool, - #[serde(flatten)] - other: HashMap, + #[serde(flatten)] + other: HashMap, } // old config.json structures for migration @@ -49,24 +49,37 @@ pub struct OldConfig { impl OldConfig { pub fn migrate(&self) -> Config { - let profiles = self.installations.as_ref().map(|insts| { - insts.iter().map(|inst| RefCell::from(Profile { - name: inst.executable - .strip_suffix(".exe") - .unwrap_or(&inst.executable) - .into(), - gd_path: inst.path.clone(), - other: HashMap::new() - })).collect::>() - }).unwrap_or(Vec::new()); + let profiles = self + .installations + .as_ref() + .map(|insts| { + insts + .iter() + .map(|inst| { + RefCell::from(Profile { + name: inst + .executable + .strip_suffix(".exe") + .unwrap_or(&inst.executable) + .into(), + gd_path: inst.path.clone(), + other: HashMap::new(), + }) + }) + .collect::>() + }) + .unwrap_or_default(); Config { - current_profile: profiles.get( - self.working_installation.unwrap_or(self.default_installation) - ).map(|i| i.borrow().name.clone()), + current_profile: profiles + .get( + self.working_installation + .unwrap_or(self.default_installation), + ) + .map(|i| i.borrow().name.clone()), profiles, default_developer: self.default_developer.to_owned(), sdk_nightly: false, - other: HashMap::new() + other: HashMap::new(), } } } @@ -74,13 +87,16 @@ impl OldConfig { pub fn geode_root() -> PathBuf { // get data dir per-platform let data_dir: PathBuf; - #[cfg(windows)] { + #[cfg(windows)] + { data_dir = dirs::data_local_dir().unwrap().join("Geode"); }; - #[cfg(target_os = "macos")] { + #[cfg(target_os = "macos")] + { data_dir = PathBuf::from("/Users/Shared/Geode"); }; - #[cfg(not(any(windows, target_os = "macos")))] { + #[cfg(not(any(windows, target_os = "macos")))] + { use std::compile_error; compile_error!("implement root directory"); }; @@ -92,7 +108,7 @@ impl Profile { Profile { name, gd_path: location, - other: HashMap::::new() + other: HashMap::::new(), } } } @@ -100,7 +116,7 @@ impl Profile { impl Config { pub fn get_profile(&self, name: &Option) -> Option<&RefCell> { if let Some(name) = name { - self.profiles.iter().filter(|x| x.borrow().name == name.to_owned()).next() + self.profiles.iter().find(|x| &x.borrow().name == name) } else { None } @@ -109,7 +125,7 @@ impl Config { pub fn sdk_path() -> PathBuf { let sdk_var = std::env::var("GEODE_SDK") .nice_unwrap("Unable to find Geode SDK. Please define the GEODE_SDK enviroment variable to point to the Geode SDK"); - + let path = PathBuf::from(sdk_var); if !path.is_dir() { fail!("The GEODE_SDK enviroment variable must point to the folder containing the Geode SDK"); @@ -126,7 +142,6 @@ Perhaps you are on a version older than v0.4.2?" path } - pub fn new() -> Config { if !geode_root().exists() { warn!("It seems you don't have Geode installed. Some operations will not work"); @@ -137,7 +152,7 @@ Perhaps you are on a version older than v0.4.2?" profiles: Vec::new(), default_developer: None, sdk_nightly: false, - other: HashMap::::new() + other: HashMap::::new(), }; } @@ -151,12 +166,12 @@ Perhaps you are on a version older than v0.4.2?" profiles: Vec::new(), default_developer: None, sdk_nightly: false, - other: HashMap::::new() + other: HashMap::::new(), } } else { // Parse config - let config_json_str = &std::fs::read_to_string(&config_json) - .nice_unwrap("Unable to read config.json"); + let config_json_str = + &std::fs::read_to_string(&config_json).nice_unwrap("Unable to read config.json"); match serde_json::from_str(config_json_str) { Ok(json) => json, Err(e) => { @@ -187,12 +202,14 @@ Perhaps you are on a version older than v0.4.2?" std::fs::create_dir_all(geode_root()).nice_unwrap("Unable to create Geode directory"); std::fs::write( geode_root().join("config.json"), - serde_json::to_string(self).unwrap() - ).nice_unwrap("Unable to save config"); + serde_json::to_string(self).unwrap(), + ) + .nice_unwrap("Unable to save config"); } pub fn rename_profile(&mut self, old: &str, new: String) { - let profile = self.get_profile(&Some(String::from(old))) + let profile = self + .get_profile(&Some(String::from(old))) .nice_unwrap(format!("Profile named '{}' does not exist", old)); if self.get_profile(&Some(new.to_owned())).is_some() { diff --git a/src/util/logging.rs b/src/util/logging.rs index 885fd70..634ab33 100644 --- a/src/util/logging.rs +++ b/src/util/logging.rs @@ -42,17 +42,17 @@ macro_rules! done { } pub trait NiceUnwrap { - fn nice_unwrap(self, text: S) -> T; + fn nice_unwrap(self, text: S) -> T; } impl NiceUnwrap for Result { - fn nice_unwrap(self, text: S) -> T { - self.unwrap_or_else(|e| fatal!("{}: {}", text, e)) - } + fn nice_unwrap(self, text: S) -> T { + self.unwrap_or_else(|e| fatal!("{}: {}", text, e)) + } } impl NiceUnwrap for Option { - fn nice_unwrap(self, text: S) -> T { - self.unwrap_or_else(|| fatal!("{}", text)) - } + fn nice_unwrap(self, text: S) -> T { + self.unwrap_or_else(|| fatal!("{}", text)) + } } diff --git a/src/util/mod.rs b/src/util/mod.rs index 2acee1f..5573e78 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,9 +1,9 @@ +pub mod bmfont; pub mod cache; pub mod config; pub mod logging; pub mod mod_file; -pub mod spritesheet; -pub mod bmfont; pub mod rgba4444; +pub mod spritesheet; pub use logging::NiceUnwrap; diff --git a/src/util/mod_file.rs b/src/util/mod_file.rs index 9f61fb7..22d1b89 100644 --- a/src/util/mod_file.rs +++ b/src/util/mod_file.rs @@ -1,30 +1,30 @@ +use serde_json::Value; use std::collections::HashMap; use std::path::{Path, PathBuf}; -use serde_json::{Value}; -use crate::{warn, fatal}; -use crate::{NiceUnwrap}; use crate::spritesheet::SpriteSheet; +use crate::NiceUnwrap; +use crate::{fatal, warn}; pub struct BitmapFont { - pub name: String, - pub path: PathBuf, - pub charset: Option, - pub size: u32, - pub outline: u32, + pub name: String, + pub path: PathBuf, + pub charset: Option, + pub size: u32, + pub outline: u32, } pub struct ModResources { pub files: Vec, pub spritesheets: HashMap, pub sprites: Vec, - pub fonts: HashMap + pub fonts: HashMap, } pub struct ModFileInfo { - pub name: String, - pub id: String, - pub resources: ModResources, + pub name: String, + pub id: String, + pub resources: ModResources, } /// Reusability for get_mod_resources @@ -36,14 +36,18 @@ fn collect_globs(value: &Value, value_name: &str, root_path: &Path, out: &mut Ve // Iterate paths for (i, entry) in value.as_array().unwrap().iter().enumerate() { // Ensure path is a string - let mut path = PathBuf::from(entry.as_str().nice_unwrap(format!("{}[{}]: Expected string", value_name, i))); + let mut path = PathBuf::from( + entry + .as_str() + .nice_unwrap(format!("{}[{}]: Expected string", value_name, i)), + ); // Absolutize if path.is_relative() { path = root_path.join(path); } - // Reusability for next + // Reusability for next let glob_err = format!("{}[{}]: Could not parse glob pattern", value_name, i); // Evaluate glob pattern @@ -63,7 +67,7 @@ fn get_mod_resources(root: &Value, root_path: &Path) -> ModResources { files: vec![], sprites: vec![], spritesheets: HashMap::new(), - fonts: HashMap::new() + fonts: HashMap::new(), }; if let Value::Object(ref resources) = root["resources"] { @@ -71,11 +75,21 @@ fn get_mod_resources(root: &Value, root_path: &Path) -> ModResources { for (key, value) in resources { match key.as_str() { "files" => { - collect_globs(value, "[mod.json].resources.files", root_path, &mut out.files); - }, + collect_globs( + value, + "[mod.json].resources.files", + root_path, + &mut out.files, + ); + } "sprites" => { - collect_globs(value, "[mod.json].resources.files", root_path, &mut out.sprites); + collect_globs( + value, + "[mod.json].resources.files", + root_path, + &mut out.sprites, + ); } "spritesheets" => { @@ -86,12 +100,20 @@ fn get_mod_resources(root: &Value, root_path: &Path) -> ModResources { // Iterate spritesheets for (name, files) in value.as_object().unwrap() { if out.spritesheets.get(name).is_some() { - fatal!("[mod.json].resources.spritesheets: Duplicate name '{}'", name); + fatal!( + "[mod.json].resources.spritesheets: Duplicate name '{}'", + name + ); } let mut sheet_files = Vec::::new(); - collect_globs(files, &format!("[mod.json].resources.spritesheets.{}", name), root_path, &mut sheet_files); + collect_globs( + files, + &format!("[mod.json].resources.spritesheets.{}", name), + root_path, + &mut sheet_files, + ); for (i, file) in sheet_files.iter().enumerate() { if file.extension().and_then(|x| x.to_str()).unwrap_or("") != "png" { @@ -99,23 +121,29 @@ fn get_mod_resources(root: &Value, root_path: &Path) -> ModResources { } } - out.spritesheets.insert(name.to_string(), SpriteSheet { - name: name.to_string(), - files: sheet_files - }); + out.spritesheets.insert( + name.to_string(), + SpriteSheet { + name: name.to_string(), + files: sheet_files, + }, + ); } } "fonts" => { // Iterate fonts - for (name, info) in value.as_object().nice_unwrap("[mod.json].resources.font: Expected object") { + for (name, info) in value + .as_object() + .nice_unwrap("[mod.json].resources.font: Expected object") + { if out.fonts.get(name).is_some() { fatal!("[mod.json].resources.fonts: Duplicate name '{}'", name); } // Convenience variable let info_name = format!("[mod.json].resources.font.{}", name); - + if !info.is_object() { fatal!("{}: Expected object", info_name); } @@ -125,47 +153,55 @@ fn get_mod_resources(root: &Value, root_path: &Path) -> ModResources { path: PathBuf::new(), charset: None, size: 0, - outline: 0 + outline: 0, }; // Iterate font attributes for (key, value) in info.as_object().unwrap() { match key.as_str() { "path" => { - font.path = PathBuf::from( - value.as_str() - .nice_unwrap(format!("{}.path: Expected string", info_name)) - ); + font.path = PathBuf::from(value.as_str().nice_unwrap(format!( + "{}.path: Expected string", + info_name + ))); // Absolutize if font.path.is_relative() { font.path = root_path.join(font.path); } - }, + } "size" => { - font.size = value.as_u64() - .nice_unwrap(format!("{}.size: Expected unsigned integer", info_name)) as u32; + font.size = value.as_u64().nice_unwrap(format!( + "{}.size: Expected unsigned integer", + info_name + )) as u32; if font.size == 0 { fatal!("{}.size: Font size cannot be 0", info_name); } - }, + } "outline" => { - font.outline = value.as_u64() - .nice_unwrap(format!("{}.outline: Expected unsigned integer", info_name)) as u32; - }, + font.outline = value.as_u64().nice_unwrap(format!( + "{}.outline: Expected unsigned integer", + info_name + )) as u32; + } "charset" => { font.charset = Some( - value.as_str() - .nice_unwrap(format!("{}.charset: Expected string", info_name)) - .to_string() + value + .as_str() + .nice_unwrap(format!( + "{}.charset: Expected string", + info_name + )) + .to_string(), ); - }, + } - _ => fatal!("{}: Unknown key {}", info_name, key) + _ => fatal!("{}: Unknown key {}", info_name, key), } } @@ -179,9 +215,9 @@ fn get_mod_resources(root: &Value, root_path: &Path) -> ModResources { out.fonts.insert(name.to_string(), font); } - }, + } - _ => fatal!("[mod.json].resources: Unknown key {}", key) + _ => fatal!("[mod.json].resources: Unknown key {}", key), } } } @@ -189,13 +225,15 @@ fn get_mod_resources(root: &Value, root_path: &Path) -> ModResources { } pub fn get_mod_file_info(root: &Value, root_path: &Path) -> ModFileInfo { - let name = root.get("name") - .nice_unwrap(format!("[mod.json]: Missing required key 'name'")) + let name = root + .get("name") + .nice_unwrap("[mod.json]: Missing required key 'name'") .as_str() - .nice_unwrap(format!("[mod.json].name: Expected string")) + .nice_unwrap("[mod.json].name: Expected string") .to_string(); - let id = root.get("id") + let id = root + .get("id") .nice_unwrap("[mod.json]: Missing required key 'id'") .as_str() .nice_unwrap("[mod.json].id: Expected string") @@ -204,6 +242,6 @@ pub fn get_mod_file_info(root: &Value, root_path: &Path) -> ModFileInfo { ModFileInfo { name, id, - resources: get_mod_resources(root, root_path) + resources: get_mod_resources(root, root_path), } } diff --git a/src/util/rgba4444.rs b/src/util/rgba4444.rs index 04df609..511175a 100644 --- a/src/util/rgba4444.rs +++ b/src/util/rgba4444.rs @@ -5,18 +5,18 @@ use image::Rgba; pub struct RGBA4444; impl ColorMap for RGBA4444 { - type Color = Rgba; + type Color = Rgba; - #[inline(always)] - fn index_of(&self, _: &Rgba) -> usize { - 0 - } + #[inline(always)] + fn index_of(&self, _: &Rgba) -> usize { + 0 + } - #[inline(always)] - fn map_color(&self, color: &mut Rgba) { - color[0] = (color[0] / 15) * 15; - color[1] = (color[1] / 15) * 15; - color[2] = (color[2] / 15) * 15; - color[3] = (color[3] / 15) * 15; - } + #[inline(always)] + fn map_color(&self, color: &mut Rgba) { + color[0] = (color[0] / 15) * 15; + color[1] = (color[1] / 15) * 15; + color[2] = (color[2] / 15) * 15; + color[3] = (color[3] / 15) * 15; + } } diff --git a/src/util/spritesheet.rs b/src/util/spritesheet.rs index 2f4b74a..371a6c9 100644 --- a/src/util/spritesheet.rs +++ b/src/util/spritesheet.rs @@ -1,26 +1,26 @@ use std::collections::BTreeMap; use std::path::{Path, PathBuf}; -use image::{RgbaImage, imageops, ImageFormat}; +use image::{imageops, ImageFormat, RgbaImage}; use serde_json::json; -use texture_packer::{TexturePacker, TexturePackerConfig}; use texture_packer::exporter::ImageExporter; +use texture_packer::{TexturePacker, TexturePackerConfig}; use crate::cache::CacheBundle; use crate::rgba4444::RGBA4444; -use crate::{info, done}; use crate::NiceUnwrap; +use crate::{done, info}; use super::mod_file::ModFileInfo; pub struct Sprite { pub name: String, - pub image: RgbaImage + pub image: RgbaImage, } pub struct SheetBundle { pub png: PathBuf, - pub plist: PathBuf + pub plist: PathBuf, } pub struct SpriteSheet { @@ -31,7 +31,7 @@ pub struct SpriteSheet { pub struct SheetBundles { pub sd: SheetBundle, pub hd: SheetBundle, - pub uhd: SheetBundle + pub uhd: SheetBundle, } impl SheetBundles { @@ -39,10 +39,7 @@ impl SheetBundles { let mut plist = base.to_owned(); plist.set_extension("plist"); - SheetBundle { - png: base, - plist - } + SheetBundle { png: base, plist } } pub fn new(mut base: PathBuf) -> SheetBundles { @@ -56,7 +53,7 @@ impl SheetBundles { SheetBundles { sd: SheetBundles::new_file(base), hd: SheetBundles::new_file(hd), - uhd: SheetBundles::new_file(uhd) + uhd: SheetBundles::new_file(uhd), } } @@ -79,10 +76,10 @@ pub fn read_to_image(path: &Path) -> RgbaImage { pub fn downscale(img: &mut RgbaImage, factor: u32) { *img = imageops::resize( - img, + img, img.width() / factor, img.height() / factor, - imageops::FilterType::Lanczos3 + imageops::FilterType::Lanczos3, ); // Dither @@ -93,16 +90,17 @@ fn initialize_spritesheet_bundle( bundle: &SheetBundle, sheet: &SpriteSheet, factor: u32, - mod_info: &ModFileInfo + mod_info: &ModFileInfo, ) { // Convert all files to sprites - let mut sprites: Vec = sheet.files.iter().map(|x| { - Sprite { + let mut sprites: Vec = sheet + .files + .iter() + .map(|x| Sprite { name: x.file_stem().unwrap().to_str().unwrap().to_string(), - image: read_to_image(x) - - } - }).collect(); + image: read_to_image(x), + }) + .collect(); // Resize for sprite in &mut sprites { @@ -112,39 +110,42 @@ fn initialize_spritesheet_bundle( // Determine maximum dimensions of sprite sheet let largest_width: u32 = sprites.iter().map(|x| x.image.width()).max().unwrap(); - let mean_height = sprites.iter().map(|x| x.image.height() as f64).sum::() / sprites.len() as f64; + let mean_height = + sprites.iter().map(|x| x.image.height() as f64).sum::() / sprites.len() as f64; let width_sum = sprites.iter().map(|x| x.image.width()).sum::() as f64; let mut max_width = (width_sum * mean_height).sqrt() as u32; if max_width < largest_width { - max_width = largest_width + 2; + max_width = largest_width + 2; } // Setup texture packer let config = TexturePackerConfig { - max_width, - max_height: u32::MAX, - allow_rotation: false, - texture_outlines: false, - border_padding: 0, - ..Default::default() + max_width, + max_height: u32::MAX, + allow_rotation: false, + texture_outlines: false, + border_padding: 0, + ..Default::default() }; let mut texture_packer = TexturePacker::new_skyline(config); // Pack textures info!("Packing sprites"); - sprites.iter().for_each(|x| texture_packer.pack_ref(&x.name, &x.image).unwrap()); + sprites + .iter() + .for_each(|x| texture_packer.pack_ref(&x.name, &x.image).unwrap()); done!("Packed sprites"); let sprite_name_in_sheet = |name: &String| { // `mod.id/sprite.png` - mod_info.id.to_owned() + "/" + - name - .strip_suffix("-uhd") - .or(name.strip_suffix("-hd")) - .unwrap_or(name) + - ".png" + mod_info.id.to_owned() + + "/" + name + .strip_suffix("-uhd") + .or_else(|| name.strip_suffix("-hd")) + .unwrap_or(name) + + ".png" }; // Initialize the plist file @@ -157,7 +158,7 @@ fn initialize_spritesheet_bundle( "spriteOffset": format!("{{{}, {}}}", frame.source.x, -(frame.source.y as i32)), })) }).collect::>(); - // Using BTreeMap to make sure all packings for the same input produce + // Using BTreeMap to make sure all packings for the same input produce // identical output via sorted keys // Write plist @@ -176,24 +177,36 @@ fn initialize_spritesheet_bundle( info!("Exporting"); let exporter = ImageExporter::export(&texture_packer).unwrap(); - exporter.write_to(&mut file, ImageFormat::Png).nice_unwrap("Unable to write to png file"); - - done!("Successfully packed {}", bundle.png.with_extension("").file_name().unwrap().to_str().unwrap().bright_yellow()); + exporter + .write_to(&mut file, ImageFormat::Png) + .nice_unwrap("Unable to write to png file"); + + done!( + "Successfully packed {}", + bundle + .png + .with_extension("") + .file_name() + .unwrap() + .to_str() + .unwrap() + .bright_yellow() + ); } fn extract_from_cache( path: &Path, working_dir: &Path, cache_bundle: &mut CacheBundle, - shut_up: bool + shut_up: bool, ) { let path_name = path.to_str().unwrap(); if !shut_up { info!("Extracting '{}' from cache", path_name); } cache_bundle.extract_cached_into( - path_name, - &working_dir.join(path.file_name().unwrap().to_str().unwrap()) + path_name, + &working_dir.join(path.file_name().unwrap().to_str().unwrap()), ); } @@ -202,7 +215,7 @@ pub fn get_spritesheet_bundles( working_dir: &Path, cache: &mut Option, mod_info: &ModFileInfo, - shut_up: bool + shut_up: bool, ) -> SheetBundles { if !shut_up { info!("Fetching spritesheet {}", sheet.name.bright_yellow()); @@ -232,18 +245,18 @@ pub fn get_spritesheet_bundles( if !shut_up { info!("Sheet is not cached, building from scratch"); } - let mut bundles = SheetBundles::new(working_dir.join(sheet.name.to_string() + ".png")); - + let bundles = SheetBundles::new(working_dir.join(sheet.name.to_string() + ".png")); + // Initialize all files info!("Creating normal sheet"); - initialize_spritesheet_bundle(&mut bundles.sd, sheet, 4, &mod_info); + initialize_spritesheet_bundle(&bundles.sd, sheet, 4, mod_info); info!("Creating HD sheet"); - initialize_spritesheet_bundle(&mut bundles.hd, sheet, 2, &mod_info); + initialize_spritesheet_bundle(&bundles.hd, sheet, 2, mod_info); info!("Creating UHD sheet"); - initialize_spritesheet_bundle(&mut bundles.uhd, sheet, 1, &mod_info); + initialize_spritesheet_bundle(&bundles.uhd, sheet, 1, mod_info); done!("Built spritesheet {}", sheet.name.bright_yellow()); bundles