diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 0000000..058da65 --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,58 @@ +name: Build and Deploy Nightly + +on: + push: + branches: + - master + +jobs: + nightly: + name: Build Nightly + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install nuitka + + - name: Build with Nuitka + run: | + python -m nuitka --onefile --standalone --enable-plugin=pyside6 --output-dir=dist src/launcher.py + + - name: Package Windows build + if: matrix.os == 'windows-latest' + run: | + powershell Compress-Archive -Path dist/* -DestinationPath LCE-WQt-Launcher-Windows.zip + + - name: Package Linux build + if: matrix.os == 'ubuntu-latest' + run: | + tar -czf LCE-WQt-Launcher-Linux.tar.gz dist/* + + - name: Upload Nightly + uses: andelf/nightly-release@main + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: nightly + name: Nightly Release + body: | + Experimental nightly builds for Windows and Linux. + files: | + *.zip + *.tar.gz \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7dd4336..fc24fc1 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,6 @@ .qmake.cache .qmake.stash .qmlls.ini -.vscode .axivion Makefile* Thumbs.db @@ -288,7 +287,7 @@ tmp/ /*-debug/ /*-release/ /out/ -rc_res.py -ui_form.py +**/res_rc.py +**/ui_form.py MinecraftLCEClient/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..8881901 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "PySide: Launch", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/src/launcher.py", + "preLaunchTask": "PySide: build" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..1e6760c --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,12 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "PySide: build", + "type": "shell", + "command": "/usr/lib/qt6/uic -g python ${workspaceFolder}/src/form.ui -o ${workspaceFolder}/src/ui_form.py && /usr/lib/qt6/rcc -g python ${workspaceFolder}/res.qrc -o ${workspaceFolder}/src/res_rc.py", + "group": "build", + "problemMatcher": [] + } + ] +} diff --git a/CODE-DE-CONDUITE.md b/CODE-DE-CONDUITE.md new file mode 100644 index 0000000..998e18b --- /dev/null +++ b/CODE-DE-CONDUITE.md @@ -0,0 +1,45 @@ +# Code du respect + +## Ce document contient des renseignements importants concernant les règles du projet + +## Objectifs + +- Développement de logiciels +- Excellence technique (pas de débats politiques ni d'activisme) +- Accueil pour tous +- Contribution positive technique +- Respecter les consignes +- Accepter la diversité naturel (y compris la neurodiversité et les handicaps) +- Traiter les autres avec respect et professionnalisme +- Le contenu NSFW est interdit (sauf autorisation). + +## Inclusivité et professionnalisme + +Vous êtes bienvenue ici + +Cela signifie que vous êtes invités à contribuer et à faire partie de la communauté, peu importe votre identité, votre sexe/genre, votre origine ethnique, votre religion, votre handicap, votre neurodiversité, votre milieu, vos convictions personnelles ou vos opinions politiques. + +## Objectif + +Ce projet suit la philosophie des logiciels et les logiciels libres et open source (FLOSS). + +Les contributions doivent privilégier le code, la qualité et la collaboration avant tout. + +## Comportements inacceptables + +Le harcèlement, l'intimidation, la discrimination (y compris le capacitisme, l'homophobie et l'hétérophobie, le sexisme, quel qu'il soit) et les propos violents ne seront pas tolérés. + +Tout comportement perturbateur ou irrespectueux pourrait entraîner l'exclusion du projet. + +## Application des règles + +Nous n'avons pas d'équipe chargée d'appliquer les règles (et nous n'en voulons pas). + +Vous pouvez signaler un problème sur le système de suivi des problèmes du projet. + +Créons des logiciels ensemble ! + +Le Code de respect s'inspire du << No Code Of Conduct >> + +Dernières modifications : 16 novembre 2025 +Version Française : 15 Janvier 2026 diff --git a/assets/Launcher_medium.png b/assets/Launcher_medium.png new file mode 100644 index 0000000..5ccfcfe Binary files /dev/null and b/assets/Launcher_medium.png differ diff --git a/assets/Launcher_small.png b/assets/Launcher_small.png new file mode 100644 index 0000000..b7a7924 Binary files /dev/null and b/assets/Launcher_small.png differ diff --git a/assets/button-pressed.png b/assets/button-pressed.png new file mode 100644 index 0000000..bcd15d5 Binary files /dev/null and b/assets/button-pressed.png differ diff --git a/assets/button.png b/assets/button.png new file mode 100644 index 0000000..943946d Binary files /dev/null and b/assets/button.png differ diff --git a/assets/minecraft-lce-title.png b/assets/minecraft-lce-title.png new file mode 100644 index 0000000..ff74bbc Binary files /dev/null and b/assets/minecraft-lce-title.png differ diff --git a/assets/minecraft.png b/assets/minecraft.png new file mode 100644 index 0000000..d0ffa5c Binary files /dev/null and b/assets/minecraft.png differ diff --git a/assets/styles/minecraft.qss b/assets/styles/minecraft.qss new file mode 100644 index 0000000..df3034a --- /dev/null +++ b/assets/styles/minecraft.qss @@ -0,0 +1,18 @@ +* { + color : white; + font-family : "Monocraft" +} + +QPushButton { + border-image : url(":/assets/button.png"); + border : none; +} + +QPushButton::pressed { + border-image : url(":/assets/button-pressed.png"); + border : none; +} + +QLineEdit { + background : black; +} \ No newline at end of file diff --git a/code-of-conduct.md b/code-of-conduct.md new file mode 100644 index 0000000..5440819 --- /dev/null +++ b/code-of-conduct.md @@ -0,0 +1,45 @@ +# Code of Respect + +## This document contains important information about the rules of the project + +## Goals and Rules + +- Making Software +- Technical Merit (not doing political debates or activism) +- Making Everyone welcome +- Push the project forward +- Respect the goal and rules +- Accept natural diversity (including neurodiversity and disability) +- Treat others with respect and professionalism +- NSFW content is not allowed (except if authorized). + +## Inclusivity and Professionalism + +## You are welcome here + +This mean you are to welcome to contribute and be a part of the community regardless +of your identity, sex/gender, ethnicity, religion, disability, neurodivergence, background, +or personal beliefs or political view. + +## Focus + +This project is about software and [FLOSS](https://www.gnu.org/philosophy/free-sw.html) (Free/Libre and Open Source Software) + +Contributions should focus on code, quality, and collaboration. + +## Unacceptable Behaviour + +Harassment, bullying, intimidation, discrimination including ableism, homophobia (and heterophobia), sexism (of both male or female) and others, or violent speech will not be tolerated. + +Disruptive or disrespectful behavior may result in removal from the project. + +## Enforcement + +We have no enforcement team (nor do we want one). +You can create a issue on the project's issue tracker. + +**Let's makes software togethers !** + +The Code of Respect is inspired by the [No Code of Conduct](https://nocodeofconduct.com) + +## Last Changes: 16 November 2025 diff --git a/form.ui b/form.ui deleted file mode 100644 index 9a21e3b..0000000 --- a/form.ui +++ /dev/null @@ -1,239 +0,0 @@ - - - launcher - - - - 0 - 0 - 800 - 600 - - - - Minecraft LCE QT Launcher - - - - :/assets/assets/Launcher.png:/assets/assets/Launcher.png - - - false - - - - - Adwaita Sans - - - - false - - - - - 30 - 30 - 751 - 337 - - - - - - - - - - - - :/assets/assets/Launcher.png - - - - - - - - 50 - 50 - - - - - Adwaita Sans - 31 - - - - LCE QT Launcher - - - - - - - - - Play - - - - - - - - - - - 0 - 0 - 800 - 22 - - - - - File - - - - - - - Help - - - - - - - - Instances - - - - - - Profiles - - - - - - Plugins - - - - - - News - - - - - - Settings - - - - - - - - - - - - - - - - - Quit - - - Quit the app - - - QAction::MenuRole::QuitRole - - - - - - - - Update - - - Update The App - - - QAction::MenuRole::ApplicationSpecificRole - - - - - - - - About - - - QAction::MenuRole::AboutRole - - - - - - - - About Qt - - - QAction::MenuRole::AboutQtRole - - - - - - - - System Information - - - QAction::MenuRole::ApplicationSpecificRole - - - - - Coming Soon - - - - - Coming Soon - - - - - Coming soon - - - - - Coming soon - - - - - Coming Soon - - - - - - - - diff --git a/pyproject.toml b/pyproject.toml index 9a9e279..62588ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,16 +1,22 @@ [project] name = "LCE-Qt-Launcher" +version = "0.0.0" +description = "This is a custom MCLCE Launcher written in python and Qt with Freedom and GNU/Linux support in mind." [tool.pyside6-project] files = [ - "config.py", - "form.ui", - "launcher.py", - "license.md", + "src/app_config.py", + "src/config.py", + "src/downloader.py", + "src/instance_manager.py", + "src/launcher.py", + "src/system_manager.py", + "src/form.ui", "pkg/LCE-Qt-Launcher.desktop", + "license.md", "readme.md", "requirements.txt", "res.qrc", - "setup.bat", - "setup.sh", + "CODE-DE-CONDUITE.md", + "code-of-conduct.md" ] diff --git a/readme.md b/readme.md index 2468f79..419d2f7 100644 --- a/readme.md +++ b/readme.md @@ -6,5 +6,25 @@ This is a custom MCLCE Launcher written in python and Qt with Freedom and GNU/Linux support in mind. +## Software Requirement + +- Pythom 3.10 and later +- PySide6 and its tool +- [Monocraft Font](https://github.com/IdreesInc/Monocraft) installed +- A display server or compositor (for Unix like system, MacOS and Windows use their own proprietary one) + + +## Compatible Operating System + +- Windows 10 and later (not tested yet) +- GNU/Linux +- MacOS (not officially supported, since I cannot test it, but should work with POISX compatibility) +- Android (not tested yet) + +## Code of Respect + +- [English](code-of-respect.md) +- [French](CODE-DE-CONDUITE.md) + ## License [GPLV3](license.md) diff --git a/res.qrc b/res.qrc index 918e865..709d259 100644 --- a/res.qrc +++ b/res.qrc @@ -1,6 +1,15 @@ - assets/Launcher.png - assets/background.png + assets/Launcher_small.png + assets/background.png + assets/Launcher_medium.png + assets/Launcher.png + assets/minecraft.png + assets/minecraft-lce-title.png + assets/button.png + assets/button-pressed.png + + + assets/styles/minecraft.qss diff --git a/setup.bat b/setup.bat deleted file mode 100644 index 3ebeadf..0000000 --- a/setup.bat +++ /dev/null @@ -1,3 +0,0 @@ -pyside6-uic form.ui -o ui_form.py - -python -m pip install -r requirement.txt diff --git a/setup.sh b/setup.sh deleted file mode 100755 index 76efc6f..0000000 --- a/setup.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/sh - -pyside6-uic form.ui -o ui_form.py - -python -m pip install -r requirement.txt diff --git a/src/app_config.py b/src/app_config.py new file mode 100644 index 0000000..cd30e32 --- /dev/null +++ b/src/app_config.py @@ -0,0 +1,36 @@ +from PySide6.QtCore import qVersion + +import subprocess + +from system_manager import SystemManager + +GITHUB_RELEASE_STR = "/releases/download/" + +LAUNCHER_REPO = "https://github.com/xgui4/LCE_QT_Launcher" + + +#LAUNCHER_STRING : str = config.get__instance_url() + \ +# GITHUB_RELEASE_STR + \ +# config.get_instance_version() + "/" + \ +# config.get_instance_archive() + +def get_git_branch(): + try: + return subprocess.run( + ["git", "rev-parse", "--aabbrev-ref", "HEAD"], + capture_output=True, + text=True, + check=True + ) + except: + print("Not a developpement version") + return "" + + +class AppConfig: + def __init__(self): + self.version : str = get_git_branch(), + self.name : str = "Minecraft LCE QT Launcher", + self.version_type : str = "pre-alpha", + self.qt_version : str = qVersion(), + self.system_manager : SystemManager = SystemManager() diff --git a/config.py b/src/config.py similarity index 98% rename from config.py rename to src/config.py index c0b3a9e..5323178 100644 --- a/config.py +++ b/src/config.py @@ -2,12 +2,11 @@ from PySide6.QtCore import QSettings class Config (QSettings): def __init__(self): - super().__init__(QSettings.NativeFormat, QSettings.UserScope, "Xgui4", "LCE QT Laucher") + super().__init__(QSettings.NativeFormat, QSettings.UserScope, "Xgui4", "LCE-QT-Laucher") def set_instance_url(self, url_str : str): super().setValue("instances/repo", url_str) super().sync() - def set_instance_exe_name(self, filename : str): super().setValue("instances/filename", filename) super().sync() @@ -34,16 +33,12 @@ class Config (QSettings): def get__instance_url(self) -> str: return self.value("instances/repo", "https://github.com/smartcmd/MinecraftConsoles"); - def get_instance_name(self) -> str: return self.value("instances/name", "default") - def get_instance_exe_name(self) -> str: return self.value("instances/filename", "Minecraft.Client.exe") - def get_instance_archive(self) -> str: return self.value("instances/archive", "LCEWindows64.zip") - def get_instance_version(self) -> str: return self.value("instances/version", "default") diff --git a/src/downloader.py b/src/downloader.py new file mode 100644 index 0000000..4161c1b --- /dev/null +++ b/src/downloader.py @@ -0,0 +1,25 @@ +from instance_manager import Instance + +import requests +import zipfile +import io + +SUCCESS_STATUS_CODE = 200 + +class Downloader: + def __init__(self, instance : Instance): + self.instance: Instance = instance + + def download_client(self): + response = requests.get(self.instance) + + if response.status_code == SUCCESS_STATUS_CODE: + try: + with zipfile.ZipFile(io.BytesIO(response.content)) as archive: + archive.extractall(self.installation_path) + except zipfile.BadZipFile as err: + print(f"Error : {err} while extracting {archive.filename}") + except zipfile.zipfile.LargeZipFile as err: + print(f"Error : {archive.filename} was too big.") + else: + print(f"Error : {response.status_code} during the dowbloading of the Minecraft LCE Client") \ No newline at end of file diff --git a/src/form.ui b/src/form.ui new file mode 100644 index 0000000..4713610 --- /dev/null +++ b/src/form.ui @@ -0,0 +1,376 @@ + + + launcher + + + + 0 + 0 + 800 + 600 + + + + + Adwaita Sans + + + + Minecraft LCE QT Launcher + + + + :/assets/launcher_small.png:/assets/launcher_small.png + + + false + + + + + Adwaita Sans + + + + false + + + + + 10 + 100 + 781 + 381 + + + + + + + + 0 + 86 + + + + Username + + + + + + + + + + Path + + + + + + + + + + Server IP + + + + + + + + + + Server Name + + + + + + + + + + Play + + + + + + + Install + + + + + + + Setting + + + + + + + + + 30 + 520 + 751 + 23 + + + + Installation Progress Bar + + + The percentage of the installation + + + install progress bar + + + 0 + + + false + + + + + + 30 + 500 + 131 + 17 + + + + Progress + + + + + + 160 + 0 + 461 + 101 + + + + + 50 + 50 + + + + + Adwaita Sans + 31 + + + + + + + :/assets/minecraft_lce_titl;e.png + + + + + + + + 0 + 0 + 800 + 27 + + + + + File + + + + + + + + + Help + + + + + + + + + + Instances + + + + + + Plugins + + + + + + News + + + + + + View + + + + + + + + + + + + + + + Quit + + + Quit the app + + + QAction::MenuRole::QuitRole + + + + + + + + Update + + + Update The App + + + QAction::MenuRole::ApplicationSpecificRole + + + + + + + + About + + + QAction::MenuRole::AboutRole + + + + + + + + About Qt + + + QAction::MenuRole::AboutQtRole + + + + + + + + System Information + + + QAction::MenuRole::ApplicationSpecificRole + + + + + Coming Soon + + + + + Coming Soon + + + + + Coming soon + + + + + Coming soon + + + + + Coming Soon + + + + + Default + + + + + + :/assets/minecraft.png + + + + About Minecraft + + + + + + + + More Minecraft LCE Projects + + + + + Save Instance + + + + + Create New Instance + + + + + usernameInputBox + pathInputBox + serverIPInputBox + serverNameInputBox + playButton + installButton + settingButton + + + + + + + diff --git a/src/instance_manager.py b/src/instance_manager.py new file mode 100644 index 0000000..2a3eea0 --- /dev/null +++ b/src/instance_manager.py @@ -0,0 +1,30 @@ +from enum import Enum + +class InstanceType(Enum): + GITHUB_RELEASE = 0 + GITHUB_SOURCE = 1 + LOCAL_NO_INSTALL = 2 + +class Instance: + def __init__(self, + name : str, + installation_path : str, + exe_name : str, + url : str, + instance_type : InstanceType, + version : str, + skin_path : str, + servers : list + ): + self.name = name + self.installation_path = installation_path + self.exe_name = exe_name + self.url = url + self.instance_type = instance_type + self.version = version + self.skin_path = skin_path + self.servers = servers + +class InstanceManager: + def __init__(self): + pass diff --git a/launcher.py b/src/launcher.py similarity index 60% rename from launcher.py rename to src/launcher.py index 84ee487..3498f25 100755 --- a/launcher.py +++ b/src/launcher.py @@ -2,29 +2,23 @@ import sys -from PySide6.QtWidgets import QApplication, QMainWindow +from PySide6.QtWidgets import QApplication, QMainWindow, QLabel from PySide6.QtGui import QPalette, QPixmap, QBrush from config import Config +from app_config import AppConfig import webbrowser -import requests -import zipfile -import io -import subprocess config = Config() -LAUNCHER_REPO = "https://github.com/xgui4/LCE_QT_Launcher" +appConfig = AppConfig() + -LAUNCHER_STRING = config.get__instance_url() + \ - "/releases/download/" + \ - config.get_instance_version() + "/" + \ - config.get_instance_archive() SUCCESS_STATUS_CODE = 200 -BACKGROUND_PIXMAP_IMG = ":/assets/assets/background.png" +BACKGROUND_PIXMAP_IMG = ":/assets/background.png" GEN_CONFIG_CMD_ARG = "--gen-config" GEN_CONFIG_CMD_ARG_SHORT = "-g" @@ -53,35 +47,11 @@ HELP_STR = """ """ def launch(): - config = Config() - print(f"Lauching {config.get_instance_name()} {config.get_instance_version()}") - - print(f"Downloading {LAUNCHER_STRING}.") - - response = requests.get(LAUNCHER_STRING) - - if response.status_code == SUCCESS_STATUS_CODE: - try: - with zipfile.ZipFile(io.BytesIO(response.content)) as archive: - archive.extractall("./MinecraftLCEClient") - except zipfile.BadZipFile as err: - print(f"Error : {err}") - except zipfile.zipfile.LargeZipFile as err: - print(f"Error : {err}") - else: - client = f"./MinecraftLCEClient/{config.get_instance_exe_name}" - print(f"Launching {client}") - subprocess.run(client) - else: - print(f"Error : {response.status_code} during the dowbloading of the Minecraft LCE Client") + print("not implemented yet!") def update_page(): - webbrowser.open_new_tab(LAUNCHER_REPO) + webbrowser.open_new_tab(config.LAUNCHER_REPO) -# Important: -# You need to run the following command to generate the ui_form.py file -# pyside6-uic form.ui -o ui_form.py, or -# pyside2-uic form.ui -o ui_form.py from ui_form import Ui_launcher class launcher(QMainWindow): @@ -97,13 +67,12 @@ class launcher(QMainWindow): self.ui = Ui_launcher() self.ui.setupUi(self) - self.ui.actionQuit.triggered.connect(app.quit) self.ui.playButton.clicked.connect(launch) - self.ui.actionUpdate.triggered.connect(update_page) - self.ui.actionAbout.triggered.connect(self.createPopupMenu) + self.versionlabel = QLabel(f"Version {VERSION}") + self.ui.statusbar.addPermanentWidget(self.versionlabel) if __name__ == "__main__": if len(sys.argv) > 1: @@ -120,6 +89,13 @@ if __name__ == "__main__": print(HELP_STR) else: app = QApplication(sys.argv) + + try: + with open("assets/styles/minecraft.qss", "r") as file: + app.setStyleSheet(file.read()) + except FileNotFoundError: + print(f"Error : qrc:/styles/minecraft.qss file not found. Reverting to default theme") + widget = launcher() widget.show() sys.exit(app.exec()) diff --git a/src/system_manager.py b/src/system_manager.py new file mode 100644 index 0000000..72bf214 --- /dev/null +++ b/src/system_manager.py @@ -0,0 +1,26 @@ +from enum import StrEnum + +import platform + +class OperatingSystemType(StrEnum): + WINDOWS = "Microsoft Windows", + MACOS = "MacOS", + LINUX = "GNU/Linux", + FREEBSD = "FreeBSD", + ANDROID = "Android" + +class SystemManager(): + def __init__(self): + self.type : OperatingSystemType = None + self.name : str = None + self.version : str = None + + def determine_os_type() -> OperatingSystemType : + if (platform.system() == "Linux") : + return OperatingSystemType.LINUX + if (platform.system() == "Darwin") : + return OperatingSystemType.MACOS + if (platform.system() == "Windows") : + return OperatingSystemType.WINDOWS + if (platform.system() == "Android") : + return OperatingSystemType.WINDOWS