First commit
This commit is contained in:
commit
06a8fcd807
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
1434
Cargo.lock
generated
Normal file
1434
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
14
Cargo.toml
Normal file
14
Cargo.toml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[package]
|
||||||
|
name = "launcher"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.75"
|
||||||
|
glob = "0.3.1"
|
||||||
|
reqwest = { version = "0.11.22", features = ["blocking"] }
|
||||||
|
zip = "0.6.6"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
winres = "0.1.12"
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Launcher
|
||||||
|
|
||||||
|
Le code est moche et pas commenté mais tkt j'ai fais ça en une soirée j'avais la fleme
|
7
build.rs
Normal file
7
build.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
fn main() {
|
||||||
|
if cfg!(target_os = "windows") {
|
||||||
|
let mut res = winres::WindowsResource::new();
|
||||||
|
res.set_icon("icon.ico");
|
||||||
|
res.compile().unwrap();
|
||||||
|
}
|
||||||
|
}
|
100
src/lib.rs
Normal file
100
src/lib.rs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
use anyhow::Context;
|
||||||
|
use reqwest::{blocking::Client, Method};
|
||||||
|
use std::{
|
||||||
|
fs::{self, File},
|
||||||
|
io,
|
||||||
|
};
|
||||||
|
|
||||||
|
use reqwest::Url;
|
||||||
|
use zip::ZipArchive;
|
||||||
|
|
||||||
|
fn get_remote_size(name: &str) -> anyhow::Result<u64> {
|
||||||
|
Ok(Client::new()
|
||||||
|
.execute(reqwest::blocking::Request::new(
|
||||||
|
Method::HEAD,
|
||||||
|
Url::parse(&format!("https://tipragot.fr/paimon/{name}.zip"))?,
|
||||||
|
))?
|
||||||
|
.headers()
|
||||||
|
.get("content-length")
|
||||||
|
.context("failed to get content-length")?
|
||||||
|
.to_str()?
|
||||||
|
.parse()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn download(name: &str) -> anyhow::Result<()> {
|
||||||
|
let file_size = get_remote_size(name)?;
|
||||||
|
if let Ok(metadata) = fs::metadata(format!("downloads/{name}.zip")) {
|
||||||
|
if metadata.len() == file_size {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("Downloading {name} ({} Mo)", file_size / 1000000);
|
||||||
|
fs::create_dir_all("downloads")?;
|
||||||
|
reqwest::blocking::get(format!("https://tipragot.fr/paimon/{name}.zip"))?
|
||||||
|
.error_for_status()?
|
||||||
|
.copy_to(&mut File::create(format!("downloads/{name}.zip"))?)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_zip(name: &str) -> anyhow::Result<()> {
|
||||||
|
// Open the archive
|
||||||
|
let mut archive = ZipArchive::new(File::open(format!("downloads/{name}.zip"))?)?;
|
||||||
|
|
||||||
|
// Get all folders in the archive
|
||||||
|
let mut exact_folders = Vec::new();
|
||||||
|
for i in 0..archive.len() {
|
||||||
|
let zip_file = archive.by_index(i)?;
|
||||||
|
if zip_file.is_dir() && zip_file.comment() == "exact" {
|
||||||
|
exact_folders.push(zip_file.name().to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract files
|
||||||
|
let mut exact_files = Vec::new();
|
||||||
|
for i in 0..archive.len() {
|
||||||
|
let mut zip_file = archive.by_index(i)?;
|
||||||
|
|
||||||
|
if zip_file.is_dir() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = zip_file
|
||||||
|
.enclosed_name()
|
||||||
|
.context("invalid filename")?
|
||||||
|
.to_owned();
|
||||||
|
for exact_folder in &exact_folders {
|
||||||
|
if path.starts_with(exact_folder) {
|
||||||
|
exact_files.push(path.clone());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the file is already up to date
|
||||||
|
if let Ok(metadata) = fs::metadata(&path) {
|
||||||
|
if zip_file.comment() == "once" || metadata.len() == zip_file.size() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(parent) = path.parent() {
|
||||||
|
fs::create_dir_all(parent)?;
|
||||||
|
}
|
||||||
|
let mut out_file = File::create(&path)?;
|
||||||
|
io::copy(&mut zip_file, &mut out_file)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove orphan files
|
||||||
|
for exact_folder in exact_folders {
|
||||||
|
for file in glob::glob(&format!("{exact_folder}/**/*"))? {
|
||||||
|
let file = file?;
|
||||||
|
if file.is_dir() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !exact_files.contains(&file) {
|
||||||
|
fs::remove_file(file)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
59
src/main.rs
Normal file
59
src/main.rs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
use launcher::{apply_zip, download};
|
||||||
|
use std::env;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::{env::set_current_dir, fs, io, process::Command};
|
||||||
|
|
||||||
|
fn main() -> anyhow::Result<()> {
|
||||||
|
// Move to the project directory
|
||||||
|
let project_folder = Path::new(&env::var("APPDATA")?).join(".paimon");
|
||||||
|
fs::create_dir_all(&project_folder)?;
|
||||||
|
set_current_dir(project_folder)?;
|
||||||
|
|
||||||
|
// Get the player username
|
||||||
|
let username = match fs::read_to_string("username.txt") {
|
||||||
|
Ok(username) => username,
|
||||||
|
Err(_) => {
|
||||||
|
print!("Enter your username: ");
|
||||||
|
io::stdout().flush()?;
|
||||||
|
let mut username = String::new();
|
||||||
|
io::stdin().read_line(&mut username)?;
|
||||||
|
fs::write("username.txt", username.trim())?;
|
||||||
|
username
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Download all the zip files
|
||||||
|
download("runtime")?;
|
||||||
|
download("libraries")?;
|
||||||
|
download("assets")?;
|
||||||
|
download("config")?;
|
||||||
|
download("mods")?;
|
||||||
|
|
||||||
|
// Apply all the zip files
|
||||||
|
println!("Updating...");
|
||||||
|
apply_zip("runtime")?;
|
||||||
|
apply_zip("libraries")?;
|
||||||
|
apply_zip("assets")?;
|
||||||
|
apply_zip("config")?;
|
||||||
|
apply_zip("mods")?;
|
||||||
|
|
||||||
|
// Launch the game
|
||||||
|
println!("Launching game...");
|
||||||
|
set_current_dir("data/game")?;
|
||||||
|
Command::new("../runtime/bin/java.exe")
|
||||||
|
.args([
|
||||||
|
"-cp",
|
||||||
|
"../libraries/*",
|
||||||
|
"net.fabricmc.loader.impl.launch.knot.KnotClient",
|
||||||
|
"--assetsDir",
|
||||||
|
"../assets",
|
||||||
|
"--assetIndex",
|
||||||
|
"5",
|
||||||
|
"--username",
|
||||||
|
username.trim(),
|
||||||
|
])
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in a new issue