Compare commits

..

No commits in common. "main" and "Release" have entirely different histories.

4 changed files with 121 additions and 155 deletions

View File

@ -1,52 +0,0 @@
name: Build Release Executables
on:
release:
types:
- created
jobs:
build-release-windows:
name: Build on Windows ${{ github.event.release.tag_name }}
runs-on: windows-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v2
- uses: actions-rs/cargo@v1
with:
command: build
args: --release
- name: Rename executable
run: mv target/release/syntax_bootstrapper.exe target/release/SyntaxPlayerLauncher.exe
- name: Upload Release Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: target/release/SyntaxPlayerLauncher.exe
asset_name: SyntaxPlayerLauncher.exe
asset_content_type: application/octet-stream
build-release-linux:
name: Build on Linux ${{ github.event.release.tag_name }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v2
- uses: actions-rs/cargo@v1
with:
command: build
args: --release
- name: Rename executable
run: mv target/release/syntax_bootstrapper target/release/SyntaxPlayerLinuxLauncher
- name: Upload Release Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: target/release/SyntaxPlayerLinuxLauncher
asset_name: SyntaxPlayerLinuxLauncher
asset_content_type: application/octet-stream

7
Cargo.lock generated
View File

@ -1178,9 +1178,9 @@ dependencies = [
[[package]] [[package]]
name = "sha1" name = "sha1"
version = "0.10.6" version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cpufeatures", "cpufeatures",
@ -1261,7 +1261,7 @@ dependencies = [
[[package]] [[package]]
name = "syntax_bootstrapper" name = "syntax_bootstrapper"
version = "1.3.3" version = "1.1.3"
dependencies = [ dependencies = [
"chrono", "chrono",
"colored", "colored",
@ -1271,7 +1271,6 @@ dependencies = [
"indicatif", "indicatif",
"md5", "md5",
"reqwest", "reqwest",
"sha1",
"term_size", "term_size",
"tokio", "tokio",
"winreg 0.51.0", "winreg 0.51.0",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "syntax_bootstrapper" name = "syntax_bootstrapper"
version = "1.3.3" version = "1.1.3"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -17,7 +17,6 @@ tokio = { version = "1.32.0", features=["full"]}
futures-util = "0.3.28" futures-util = "0.3.28"
md5 = "0.7.0" md5 = "0.7.0"
zip-extract = "0.1.2" zip-extract = "0.1.2"
sha1 = "0.10.6"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winreg = "0.51.0" winreg = "0.51.0"

View File

@ -1,4 +1,3 @@
use chrono::format;
use colored::*; use colored::*;
use std::path::PathBuf; use std::path::PathBuf;
use reqwest::Client; use reqwest::Client;
@ -6,7 +5,6 @@ use dirs::data_local_dir;
use futures_util::StreamExt; use futures_util::StreamExt;
use md5; use md5;
use zip_extract; use zip_extract;
use sha1::{Sha1, Digest};
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use std::os::windows::prelude::FileExt; use std::os::windows::prelude::FileExt;
@ -113,14 +111,6 @@ pub async fn create_folder_if_not_exists( path: &PathBuf ) {
} }
} }
pub async fn get_sha1_hash_of_file( path: &PathBuf ) -> String {
let mut file = std::fs::File::open(path).unwrap();
let mut hasher = Sha1::new();
std::io::copy(&mut file, &mut hasher).unwrap();
let hash = hasher.finalize();
return format!("{:x}", hash);
}
fn get_installation_directory() -> PathBuf { fn get_installation_directory() -> PathBuf {
return PathBuf::from(data_local_dir().unwrap().to_str().unwrap()).join("Syntax"); return PathBuf::from(data_local_dir().unwrap().to_str().unwrap()).join("Syntax");
} }
@ -250,63 +240,28 @@ async fn main() {
if !current_exe_path.starts_with(&current_version_directory) { if !current_exe_path.starts_with(&current_version_directory) {
// Check if the latest bootstrapper is downloaded // Check if the latest bootstrapper is downloaded
if !latest_bootstrapper_path.exists() { if !latest_bootstrapper_path.exists() {
info("Downloading the latest bootstrapper"); info("Downloading the latest bootstrapper and restarting");
// Download the latest bootstrapper // Download the latest bootstrapper
download_file(&http_client, &format!("https://{}/{}-{}", setup_url, latest_client_version, bootstrapper_filename), &latest_bootstrapper_path).await; download_file(&http_client, &format!("https://{}/{}-{}", setup_url, latest_client_version, bootstrapper_filename), &latest_bootstrapper_path).await;
} }
// Run the latest bootstrapper ( with the same arguments passed to us ) and exit
// Lets compare the SHA1 hash of the latest bootstrapper to the one we are currently running #[cfg(target_os = "windows")]
// If they are the same, then we can continue with the update process {
// We do this because antivirus software does not like this type of behavior let mut command = std::process::Command::new(latest_bootstrapper_path);
command.args(&args[1..]);
let latest_bootstrapper_hash = get_sha1_hash_of_file(&latest_bootstrapper_path).await; command.spawn().unwrap();
let current_exe_hash = get_sha1_hash_of_file(&current_exe_path).await;
debug(&format!("Latest Bootstrapper Hash: {}", latest_bootstrapper_hash.bright_blue()));
debug(&format!("Current Bootstrapper Hash: {}", current_exe_hash.bright_blue()));
if latest_bootstrapper_hash != current_exe_hash {
info("Starting latest bootstrapper");
// Run the latest bootstrapper ( with the same arguments passed to us ) and exit
#[cfg(target_os = "windows")]
{
let mut command = std::process::Command::new(latest_bootstrapper_path.clone());
command.args(&args[1..]);
match command.spawn() {
Ok(_) => {},
Err(e) => {
debug(&format!("Bootstrapper errored with error {}", e));
info("Found bootstrapper was corrupted! Downloading...");
std::fs::remove_file(latest_bootstrapper_path.clone()).unwrap();
download_file(&http_client, &format!("https://{}/{}-{}", setup_url, latest_client_version, bootstrapper_filename), &latest_bootstrapper_path).await;
command.spawn().expect("Bootstrapper is still corrupted.");
std::thread::sleep(std::time::Duration::from_secs(20));
}
}
}
#[cfg(not(target_os = "windows"))]
{
// Make sure the latest bootstrapper is executable
std::process::Command::new("chmod").arg("+x").arg(latest_bootstrapper_path.to_str().unwrap()).spawn().unwrap();
let desktop_file_content = &format!("[Desktop Entry]
Name=Syntax Launcher
Exec={} %u
Icon={}
Type=Application
Terminal=true
Version={}
MimeType=x-scheme-handler/syntax-player;", latest_bootstrapper_path.to_str().unwrap(), latest_bootstrapper_path.to_str().unwrap(), env!("CARGO_PKG_VERSION"));
let desktop_file_path = dirs::data_local_dir().unwrap().join("applications").join("syntax-player.desktop");
std::fs::write(desktop_file_path, desktop_file_content).unwrap();
info("Please launch SYNTAX from the website, to continue with the update process.");
std::thread::sleep(std::time::Duration::from_secs(20));
}
std::process::exit(0);
} }
#[cfg(not(target_os = "windows"))]
{
// Make sure the latest bootstrapper is executable
std::process::Command::new("chmod").arg("+x").arg(latest_bootstrapper_path.to_str().unwrap()).spawn().unwrap();
info("We need permission to run the latest bootstrapper");
let mut command = std::process::Command::new(latest_bootstrapper_path);
command.args(&args[1..]);
command.spawn().unwrap();
}
std::process::exit(0);
} }
// Looks like we are running from the latest version directory, so we can continue with the update process // Looks like we are running from the latest version directory, so we can continue with the update process
@ -314,13 +269,14 @@ MimeType=x-scheme-handler/syntax-player;", latest_bootstrapper_path.to_str().unw
// If it doesent exist, then we got either a fresh directory or a corrupted installation // If it doesent exist, then we got either a fresh directory or a corrupted installation
// So delete the every file in the current version directory except for the Bootstrapper itself // So delete the every file in the current version directory except for the Bootstrapper itself
let app_settings_path = current_version_directory.join("AppSettings.xml"); let app_settings_path = current_version_directory.join("AppSettings.xml");
if !app_settings_path.exists() { //|| !client_executable_path.exists() { let client_executable_path = current_version_directory.join("SyntaxPlayerBeta.exe");
if !app_settings_path.exists() || !client_executable_path.exists() {
info("Downloading the latest client files, this may take a while."); info("Downloading the latest client files, this may take a while.");
for entry in std::fs::read_dir(&current_version_directory).unwrap() { for entry in std::fs::read_dir(&current_version_directory).unwrap() {
let entry = entry.unwrap(); let entry = entry.unwrap();
let path = entry.path(); let path = entry.path();
if path.is_file() { if path.is_file() {
if path != latest_bootstrapper_path { if path != current_exe_path {
std::fs::remove_file(path).unwrap(); std::fs::remove_file(path).unwrap();
} }
} else { } else {
@ -329,35 +285,85 @@ MimeType=x-scheme-handler/syntax-player;", latest_bootstrapper_path.to_str().unw
} }
let VersionURLPrefix = format!("https://{}/{}-", setup_url, latest_client_version); let VersionURLPrefix = format!("https://{}/{}-", setup_url, latest_client_version);
let SyntaxAppZip : PathBuf = download_file_prefix(&http_client, format!("{}SyntaxApp.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let NPSyntaxProxyZip : PathBuf = download_file_prefix(&http_client, format!("{}NPSyntaxProxy.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let SyntaxProxyZip : PathBuf = download_file_prefix(&http_client, format!("{}SyntaxProxy.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let LibrariesZip : PathBuf = download_file_prefix(&http_client, format!("{}Libraries.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let RedistZip : PathBuf = download_file_prefix(&http_client, format!("{}redist.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let ContentTexturesZip : PathBuf = download_file_prefix(&http_client, format!("{}content-textures.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let ContentTextures2Zip : PathBuf = download_file_prefix(&http_client, format!("{}content-textures2.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let ContentTextures3Zip : PathBuf = download_file_prefix(&http_client, format!("{}content-textures3.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let ContentTerrainZip : PathBuf = download_file_prefix(&http_client, format!("{}content-terrain.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let ContentFontsZip : PathBuf = download_file_prefix(&http_client, format!("{}content-fonts.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let ContentSoundsZip : PathBuf = download_file_prefix(&http_client, format!("{}content-sounds.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let ContentScriptsZip : PathBuf = download_file_prefix(&http_client, format!("{}content-scripts.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let ContentSkyZip : PathBuf = download_file_prefix(&http_client, format!("{}content-sky.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let ContentMusicZip : PathBuf = download_file_prefix(&http_client, format!("{}content-music.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let ContentParticles : PathBuf = download_file_prefix(&http_client, format!("{}content-particles.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let ShadersZip : PathBuf = download_file_prefix(&http_client, format!("{}shaders.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let Client2018Zip : PathBuf = download_file_prefix(&http_client, format!("{}2018client.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await; let Client2018Zip : PathBuf = download_file_prefix(&http_client, format!("{}2018client.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let Client2020Zip : PathBuf = download_file_prefix(&http_client, format!("{}2020client.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let Client2014Zip : PathBuf = download_file_prefix(&http_client, format!("{}2014client.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
let Client2016Zip : PathBuf = download_file_prefix(&http_client, format!("{}2016client.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
info("Download finished, extracting files."); info("Download finished, extracting files.");
fn extract_to_dir( zip_file : &PathBuf, target_dir : &PathBuf ) { fn extract_to_dir( zip_file : &PathBuf, target_dir : &PathBuf ) {
info(format!("Extracting {} to {}", zip_file.to_str().unwrap().bright_blue(), target_dir.to_str().unwrap().bright_blue()).as_str());
let zip_file_cursor = std::fs::File::open(zip_file).unwrap(); let zip_file_cursor = std::fs::File::open(zip_file).unwrap();
zip_extract::extract(zip_file_cursor, target_dir, false).unwrap(); zip_extract::extract(zip_file_cursor, target_dir, false).unwrap();
} }
extract_to_dir(&SyntaxAppZip, &current_version_directory);
extract_to_dir(&NPSyntaxProxyZip, &current_version_directory);
extract_to_dir(&SyntaxProxyZip, &current_version_directory);
extract_to_dir(&LibrariesZip, &current_version_directory);
extract_to_dir(&RedistZip, &current_version_directory);
let content_directory = current_version_directory.join("content");
let platform_content_directory = current_version_directory.join("PlatformContent");
let shaders_directory = current_version_directory.join("shaders");
create_folder_if_not_exists(&content_directory).await;
create_folder_if_not_exists(&platform_content_directory).await;
create_folder_if_not_exists(&shaders_directory).await;
let fonts_directory = content_directory.join("fonts");
let music_directory = content_directory.join("music");
let particles_directory = content_directory.join("particles");
let sky_directory = content_directory.join("sky");
let sounds_directory = content_directory.join("sounds");
let textures_directory = content_directory.join("textures");
let scripts_directory = content_directory.join("scripts");
create_folder_if_not_exists(&fonts_directory).await;
create_folder_if_not_exists(&music_directory).await;
create_folder_if_not_exists(&particles_directory).await;
create_folder_if_not_exists(&sky_directory).await;
create_folder_if_not_exists(&sounds_directory).await;
create_folder_if_not_exists(&textures_directory).await;
extract_to_dir(&ContentTexturesZip, &textures_directory);
extract_to_dir(&ContentTextures2Zip, &textures_directory);
extract_to_dir(&ContentFontsZip, &fonts_directory);
extract_to_dir(&ContentSoundsZip, &sounds_directory);
extract_to_dir(&ContentSkyZip, &sky_directory);
extract_to_dir(&ContentMusicZip, &music_directory);
extract_to_dir(&ContentParticles, &particles_directory);
extract_to_dir(&ContentScriptsZip, &scripts_directory);
let platform_pc_directory = platform_content_directory.join("pc");
create_folder_if_not_exists(&platform_pc_directory).await;
let terrain_directory = platform_pc_directory.join("terrain");
let textures_directory = platform_pc_directory.join("textures");
create_folder_if_not_exists(&terrain_directory).await;
create_folder_if_not_exists(&textures_directory).await;
extract_to_dir(&ContentTerrainZip, &terrain_directory);
extract_to_dir(&ContentTextures3Zip, &textures_directory);
extract_to_dir(&ShadersZip, &shaders_directory);
let client_2018_directory = current_version_directory.join("Client2018"); let client_2018_directory = current_version_directory.join("Client2018");
create_folder_if_not_exists(&client_2018_directory).await; create_folder_if_not_exists(&client_2018_directory).await;
extract_to_dir(&Client2018Zip, &client_2018_directory); extract_to_dir(&Client2018Zip, &client_2018_directory);
let client_2020_directory = current_version_directory.join("Client2020");
create_folder_if_not_exists(&client_2020_directory).await;
extract_to_dir(&Client2020Zip, &client_2020_directory);
let client_2014_directory = current_version_directory.join("Client2014");
create_folder_if_not_exists(&client_2014_directory).await;
extract_to_dir(&Client2014Zip, &client_2014_directory);
let client_2016_directory = current_version_directory.join("Client2016");
create_folder_if_not_exists(&client_2016_directory).await;
extract_to_dir(&Client2016Zip, &client_2016_directory);
info("Finished extracting files, cleaning up."); info("Finished extracting files, cleaning up.");
std::fs::remove_dir_all(&temp_downloads_directory).unwrap(); std::fs::remove_dir_all(&temp_downloads_directory).unwrap();
@ -372,25 +378,43 @@ MimeType=x-scheme-handler/syntax-player;", latest_bootstrapper_path.to_str().unw
let hkey_syntax_player_shell_open = hkey_syntax_player_shell.create_subkey("open").unwrap().0; let hkey_syntax_player_shell_open = hkey_syntax_player_shell.create_subkey("open").unwrap().0;
let hkey_syntax_player_shell_open_command = hkey_syntax_player_shell_open.create_subkey("command").unwrap().0; let hkey_syntax_player_shell_open_command = hkey_syntax_player_shell_open.create_subkey("command").unwrap().0;
let defaulticon = hkey_syntax_player.create_subkey("DefaultIcon").unwrap().0; let defaulticon = hkey_syntax_player.create_subkey("DefaultIcon").unwrap().0;
hkey_syntax_player_shell_open_command.set_value("", &format!("\"{}\" \"%1\"", latest_bootstrapper_path.to_str().unwrap())).unwrap(); hkey_syntax_player_shell_open_command.set_value("", &format!("\"{}\" \"%1\"", current_exe_path.to_str().unwrap())).unwrap();
defaulticon.set_value("", &format!("\"{}\",0", latest_bootstrapper_path.to_str().unwrap())).unwrap(); defaulticon.set_value("", &format!("\"{}\",0", current_exe_path.to_str().unwrap())).unwrap();
hkey_syntax_player.set_value("", &format!("URL: Syntax Protocol")).unwrap(); hkey_syntax_player.set_value("", &format!("URL: Syntax Protocol")).unwrap();
hkey_syntax_player.set_value("URL Protocol", &"").unwrap(); hkey_syntax_player.set_value("URL Protocol", &"").unwrap();
} }
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
{ {
// Linux support // Linux support
let desktop_file_content = &format!("[Desktop Entry] // We have to write a .desktop file to ~/.local/share/applications
let desktop_file_path = dirs::data_local_dir().unwrap().join("applications").join("syntax-player.desktop");
let desktop_file = format!(
"[Desktop Entry]
Name=Syntax Launcher Name=Syntax Launcher
Exec={} %u Exec={} %u
Icon={}
Type=Application
Terminal=true Terminal=true
Version={} Type=Application
MimeType=x-scheme-handler/syntax-player;", latest_bootstrapper_path.to_str().unwrap(), latest_bootstrapper_path.to_str().unwrap(), env!("CARGO_PKG_VERSION")); MimeType=x-scheme-handler/syntax-player;
Icon={}
let desktop_file_path = dirs::data_local_dir().unwrap().join("applications").join("syntax-player.desktop"); StartupWMClass=SyntaxLauncher
std::fs::write(desktop_file_path, desktop_file_content).unwrap(); Categories=Game;
Comment=Syntax Launcher
", current_exe_path.to_str().unwrap(), current_exe_path.to_str().unwrap());
std::fs::write(desktop_file_path, desktop_file).unwrap();
// We also have to write a mimeapps.list file to ~/.config
let mimeapps_list_path = dirs::config_dir().unwrap().join("mimeapps.list");
let mimeapps_list = format!(
"[Default Applications]
x-scheme-handler/syntax-player=syntax-player.desktop
");
std::fs::write(mimeapps_list_path, mimeapps_list).unwrap();
// We also have to write a mimeapps.list file to ~/.local/share
let mimeapps_list_path = dirs::data_local_dir().unwrap().join("mimeapps.list");
let mimeapps_list = format!(
"[Default Applications]
x-scheme-handler/syntax-player=syntax-player.desktop
");
std::fs::write(mimeapps_list_path, mimeapps_list).unwrap();
} }
// Write the AppSettings.xml file // Write the AppSettings.xml file
@ -398,7 +422,7 @@ MimeType=x-scheme-handler/syntax-player;", latest_bootstrapper_path.to_str().unw
"<?xml version=\"1.0\" encoding=\"UTF-8\"?> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<Settings> <Settings>
<ContentFolder>content</ContentFolder> <ContentFolder>content</ContentFolder>
<BaseUrl>http://{}</BaseUrl> <BaseUrl>https://{}</BaseUrl>
</Settings>", base_url </Settings>", base_url
); );
std::fs::write(app_settings_path, app_settings_xml).unwrap(); std::fs::write(app_settings_path, app_settings_xml).unwrap();
@ -485,12 +509,8 @@ MimeType=x-scheme-handler/syntax-player;", latest_bootstrapper_path.to_str().unw
debug(&client_year.to_string()); debug(&client_year.to_string());
if client_year == "2018" { if client_year == "2018" {
client_executable_path = current_version_directory.join("Client2018").join("SyntaxPlayerBeta.exe"); client_executable_path = current_version_directory.join("Client2018").join("SyntaxPlayerBeta.exe");
} else if client_year == "2020" {
client_executable_path = current_version_directory.join("Client2020").join("SyntaxPlayerBeta.exe");
} else if client_year == "2014" {
client_executable_path = current_version_directory.join("Client2014").join("SyntaxPlayerBeta.exe");
} else { } else {
client_executable_path = current_version_directory.join("Client2016").join("SyntaxPlayerBeta.exe"); client_executable_path = current_version_directory.join("SyntaxPlayerBeta.exe");
} }
if !client_executable_path.exists() { if !client_executable_path.exists() {
// Delete AppSettings.xml so the bootstrapper will download the client again // Delete AppSettings.xml so the bootstrapper will download the client again