diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 0000000..49f3b8c --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,62 @@ +# Maintainer: Xgui4 +pkgname=lce-qt-launcher-git +pkgver=r149.804311b +pkgrel=1 +pkgdesc="A custom Minecraft LCE Launcher written in Python and Qt with GNU/Linux support in mind. (Nigthly/Git Build)" +arch=('any') +url="https://github.com/xgui4/LCE-Qt-Launcher" +license=('GPL-3.0-or-later') +depends=( + 'python' + 'pyside6' + 'python-requests' + 'python-platformdirs' + 'python-rich' +) +makedepends=( + 'git' + 'bash' + 'curl' + 'python-build' + 'python-installer' + 'python-hatchling' + 'python-wheel' + 'qt6-tools' +) +optdepends=( + 'wine: Allow to launch non-Linux-native Minecraft LCE ports' + 'steam: Allow for Steam integration' + 'ttc-monocraft: Minecraft Font for the UI (Availaible in the AUR)' +) + +provides=("${pkgname%-git}" "${pkgname%-nightly}" "${pkgname%}") +conflicts=("${pkgname%-dev}" "${pkgname%-stable}" "${pkgname%}") +source=("${pkgname}::git+${url}.git#branch=nightly") +sha256sums=('SKIP') + +pkgver() { + cd "$pkgname" + # cutting off 'foo-' prefix that presents in the git tag + git describe --long --abbrev=7 | sed 's/^foo-//;s/\([^-]*-g\)/r\1/;s/-/./g' +} + +build() { + cd "$pkgname" + rm -rf dist/ build/ + /usr/bin/python -m build --wheel --no-isolation +} + +package() { + cd "$pkgname" + /usr/bin/python -m installer --destdir="$pkgdir" dist/*.whl + install -d "$pkgdir/opt/lce_qt_launcher" + cp -r data assets "$pkgdir" + install -Dm644 "data/lce_qt_launcher.ini" "$pkgdir/etc/lce_qt_launcher.ini" + install -Dm644 "packages/io.github.xgui4.lce_qt_launcher.desktop" "$pkgdir/usr/share/applications/io.github.xgui4.lce_qt_launcher.desktop" + install -Dm644 "packages/lce_inst-mime.xml" "$pkgdir/usr/share/mime/packages/io.github.xgui4.lce_qt_launcher.gtk.metainfo.xml" + install -Dm644 "license.md" -t "$pkgdir/usr/share/licenses/$pkgname/" + install -Dm644 "readme.md" "code-of-conduct.md" -t "$pkgdir/usr/share/doc/$pkgname/" + install -Dm644 "packages/io.github.xgui4.lce_qt_launcher.metainfo.xml" "$pkgdir/usr/share/metainfo/io.github.xgui4.lce_qt_launcher.gtk.metainfo.xml" + install -Dm644 "assets/io.github.xgui4.lce_qt_launcher.png" "$pkgdir/usr/share/icons/hicolor/128x128/apps/io.github.xgui4.lce_qt_launcher.png" + install -Dm644 "assets/lce_inst.png" "$pkgdir/usr/share/icons/hicolor/128x128/mimetypes/application-x-lce_inst.png" +} diff --git a/assets/images/aether.png b/assets/images/aether.png new file mode 100644 index 0000000..69c8a62 Binary files /dev/null and b/assets/images/aether.png differ diff --git a/data/defaults_instances/aether.lce_inst b/data/defaults_instances/aether.lce_inst new file mode 100644 index 0000000..6ac7497 --- /dev/null +++ b/data/defaults_instances/aether.lce_inst @@ -0,0 +1,15 @@ +{ + "$schema": "https://raw.githubusercontent.com/xgui4/LCE-Qt-Launcher/refs/heads/nightly/schemas/x-application-lce_inst_config.json", + "name": "aRockefeler Aether Mod", + "installation_path": ".lce-aether", + "archive_file": "Release", + "username": "Steve", + "image": ":/aether.png", + "exe_name": "Minecraft.Client.exe", + "url": "https://github.com/Frcoxd/aether-papu", + "repo_url": "https://github.com/Frcoxd/aether-papu", + "news_feed": "https://github.com/LCE-Hub/LCE-Workshop/tree/main/.00versions/test", + "instance_source": "InstanceSource.GITHUB_RELEASE", + "instance_type": "InstanceType.CLIENT_VANILLA", + "version": "Aether" +} \ No newline at end of file diff --git a/data/defaults_instances/default.lce_inst b/data/defaults_instances/default.lce_inst index d07e260..196622c 100644 --- a/data/defaults_instances/default.lce_inst +++ b/data/defaults_instances/default.lce_inst @@ -6,7 +6,7 @@ "archive_file": "LCEWindows64.zip", "exe_name": "Minecraft.Client.exe", "repo_url": "https://github.com/MCLCE/MinecraftConsoles", - "image" : ":/assets/minecraft.png", + "image" : ":/assets/mclce-ico.png", "news_feed" : "https://github.com/MCLCE/MinecraftConsoles/commits/main/", "instance_source": "InstanceSource.GITHUB_RELEASE", "instance_type": "InstanceType.CLIENT_VANILLA", diff --git a/default.nix b/default.nix index ffa5403..40525a3 100644 --- a/default.nix +++ b/default.nix @@ -2,7 +2,7 @@ pkgs.python3Packages.buildPythonApplication rec { pname = "lce-qt-launcher"; - version = "2026.5.1"; + version = "2026.5.2"; format = "pyproject"; src = ./.; @@ -18,6 +18,7 @@ pkgs.python3Packages.buildPythonApplication rec { pkgs.bash pkgs.coreutils pkgs.gnused + pkgs.monocraft ]; propagatedBuildInputs = with pkgs.python3Packages; [ diff --git a/packages/windows/windows-setup-nigthly-preview.iss b/packages/windows/windows-setup-nigthly-preview.iss index 5c7f546..0e22ab8 100644 --- a/packages/windows/windows-setup-nigthly-preview.iss +++ b/packages/windows/windows-setup-nigthly-preview.iss @@ -3,7 +3,7 @@ ; Non-commercial use only #define MyAppName "LCE Qt Launcher (Nightly Preview Inno Setup 7 Installer)" -#define MyAppVersion "2026.5.1" +#define MyAppVersion "2026.5.2" #define MyAppPublisher "Xgui4" #define MyAppURL "https://github.com/xgui4/lce-qt-launcher" #define MyAppExeName "main.exe" diff --git a/packages/windows/windows-setup-nigthly.iss b/packages/windows/windows-setup-nigthly.iss index 5b528a8..44015bc 100644 --- a/packages/windows/windows-setup-nigthly.iss +++ b/packages/windows/windows-setup-nigthly.iss @@ -3,7 +3,7 @@ ; Non-commercial use only #define MyAppName "LCE Qt Launcher (Nightly)" -#define MyAppVersion "2026.5.1" +#define MyAppVersion "2026.5.2" #define MyAppPublisher "Xgui4" #define MyAppURL "https://github.com/xgui4/lce-qt-launcher" #define MyAppExeName "main.exe" diff --git a/pyproject.toml b/pyproject.toml index 51dff29..f0e36a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,10 +74,12 @@ files = [ "src/lce_qt_launcher/views/app_data.py", "src/lce_qt_launcher/managers/__init__.py", "src/lce_qt_launcher/managers/instance.py", - "src/lce_qt_launcher/managers/system_managers.py", - "src/lce_qt_launcher/managers/steam_managers.py", - "src/lce_qt_launcher/managers/proton_managers.py", - "src/lce_qt_launcher/managers/mod_managers.py", + "src/lce_qt_launcher/managers/system_manager.py", + "src/lce_qt_launcher/managers/steam_manager.py", + "src/lce_qt_launcher/managers/proton_manager.py", + "src/lce_qt_launcher/managers/mod_manager.py", + "src/lce_qt_launcher/managers/import_manager.py", + "src/lce_qt_launcher/managers/skin_manager.py", "src/lce_qt_launcher/models/__init__.py", "src/lce_qt_launcher/models/image_class.py", "src/lce_qt_launcher/models/preferences.py", diff --git a/res.qrc b/res.qrc index 24331da..886ac1e 100644 --- a/res.qrc +++ b/res.qrc @@ -20,6 +20,7 @@ assets/images/lce-hub-ico.png assets/images/chest.png assets/images/piston.png + assets/images/aether.png assets/styles/minecraft.qss @@ -33,6 +34,7 @@ data/defaults_instances/hellishends.lce_inst data/defaults_instances/360Revived.lce_inst data/defaults_instances/revelation.lce_inst + data/defaults_instances/aether.lce_inst assets/languages/translations.json diff --git a/src/lce_qt_launcher/managers/skin_manager.py b/src/lce_qt_launcher/managers/skin_manager.py new file mode 100644 index 0000000..e69de29 diff --git a/src/lce_qt_launcher/managers/steam_manager.py b/src/lce_qt_launcher/managers/steam_manager.py index 99bff09..2bc81dc 100644 --- a/src/lce_qt_launcher/managers/steam_manager.py +++ b/src/lce_qt_launcher/managers/steam_manager.py @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ - + def main(): print( """ @@ -26,5 +26,6 @@ def main(): under certain conditions; type `show c' for details. """) + if __name__ == "__main__": main() \ No newline at end of file diff --git a/src/lce_qt_launcher/managers/steam_manager.rs b/src/lce_qt_launcher/managers/steam_manager.rs new file mode 100644 index 0000000..f5f1228 --- /dev/null +++ b/src/lce_qt_launcher/managers/steam_manager.rs @@ -0,0 +1,109 @@ +#[tauri::command] +async fn add_to_steam( + _app: AppHandle, + instance_id: String, + name: String, + title_base64: String, + panorama_base64: String, +) -> Result<(), String> { + let exe_path = std::env::current_exe().map_err(|e| e.to_string())?; + let exe_str = exe_path.to_string_lossy().to_string(); + let launch_options = format!("\"{}\"", instance_id); + let start_dir = exe_path.parent().map(|p| p.to_string_lossy().to_string()).unwrap_or_default(); + let app_id_32 = steam_shortcuts_util::app_id_generator::calculate_app_id(&exe_str, &name); + //let app_id_64 = ((app_id_32 as u64) << 32) | 0x02000000; //neo: just in case we'll need later. + let mut userdata_dirs: Vec = Vec::new(); + #[cfg(target_os = "linux")] + { + if let Ok(home) = std::env::var("HOME") { + let h = PathBuf::from(home); + userdata_dirs.push(h.join(".steam/steam/userdata")); + userdata_dirs.push(h.join(".local/share/Steam/userdata")); + userdata_dirs.push(h.join(".var/app/com.valvesoftware.Steam/.local/share/Steam/userdata")); + } + } + #[cfg(target_os = "windows")] + { + userdata_dirs.push(PathBuf::from("C:\\Program Files\\Steam\\userdata")); + userdata_dirs.push(PathBuf::from("C:\\Program Files (x86)\\Steam\\userdata")); + } + #[cfg(target_os = "macos")] + { + if let Ok(home) = std::env::var("HOME") { + let h = PathBuf::from(home); + userdata_dirs.push(h.join("Library/Application Support/Steam/userdata")); + } + } + + let valid_userdata_dirs: Vec = userdata_dirs.into_iter().filter(|d| d.exists()).collect(); + if valid_userdata_dirs.is_empty() { + return Err("Steam userdata directory not found.".into()); + } + + for userdata_root in valid_userdata_dirs { + let entries = fs::read_dir(&userdata_root).map_err(|e| e.to_string())?; + for entry in entries.flatten() { + if entry.file_type().map(|t| t.is_dir()).unwrap_or(false) { + let user_config_dir = entry.path().join("config"); + let shortcuts_path = user_config_dir.join("shortcuts.vdf"); + if !user_config_dir.exists() { continue; } + let content = if shortcuts_path.exists() { + fs::read(&shortcuts_path).unwrap_or_default() + } else { + Vec::new() + }; + + let shortcuts = if !content.is_empty() { + parse_shortcuts(&content).map_err(|e| e.to_string())? + } else { + Vec::new() + }; + + let mut owned_shortcuts: Vec = shortcuts.iter().map(|s| s.to_owned()).collect(); + if owned_shortcuts.iter().any(|s| s.app_name == name && s.exe == exe_str) { + continue; + } + + owned_shortcuts.push(steam_shortcuts_util::shortcut::ShortcutOwned { + order: owned_shortcuts.len().to_string(), + app_id: app_id_32, + app_name: name.clone(), + exe: exe_str.clone(), + start_dir: start_dir.clone(), + icon: "".to_string(), + shortcut_path: "".to_string(), + launch_options: launch_options.clone(), + is_hidden: false, + allow_desktop_config: true, + allow_overlay: true, + open_vr: 0, + dev_kit: 0, + dev_kit_game_id: "".to_string(), + dev_kit_overrite_app_id: 0, + last_play_time: 0, + tags: Vec::new(), + }); + + let final_shortcuts: Vec = owned_shortcuts.iter().map(|s| s.borrow()).collect(); + let new_content = shortcuts_to_bytes(&final_shortcuts); + fs::write(&shortcuts_path, new_content).map_err(|e| e.to_string())?; + let grid_dir = user_config_dir.join("grid"); + if !grid_dir.exists() { + let _ = fs::create_dir_all(&grid_dir); + } + + if grid_dir.exists() { + let panorama_data = general_purpose::STANDARD.decode(panorama_base64.clone()).map_err(|e| e.to_string())?; + let title_data = general_purpose::STANDARD.decode(title_base64.clone()).map_err(|e| e.to_string())?; + let _ = fs::write(grid_dir.join(format!("{}p.png", app_id_32)), &panorama_data); + let _ = fs::write(grid_dir.join(format!("{}_hero.png", app_id_32)), &panorama_data); + let _ = fs::write(grid_dir.join(format!("{}.png", app_id_32)), &panorama_data); + let _ = fs::write(grid_dir.join(format!("{}_logo.png", app_id_32)), &title_data); + let _ = fs::write(grid_dir.join(format!("{}.json", app_id_32)), "{\"nVersion\":1,\"logoPosition\":{\"pinnedPosition\":\"CenterCenter\",\"nWidthPct\":50,\"nHeightPct\":50}}".as_bytes()); //neo: if you're confused, this is for logo position + } + } + } + } + + Ok(()) +} \ No newline at end of file