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