mirror of
https://github.com/xgui4/LCE-Qt-Launcher.git
synced 2026-07-18 02:30:44 +00:00
add a wip main.py launcher, update the cli , and the whole system
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -294,3 +294,4 @@ MinecraftLCEClient/
|
||||
src/LCE-Qt-Windows-Launcher.zip
|
||||
|
||||
output/
|
||||
.vscode/settings.json
|
||||
|
||||
14
.vscode/settings.json
vendored
14
.vscode/settings.json
vendored
@@ -1,3 +1,15 @@
|
||||
{
|
||||
"python-envs.defaultEnvManager": "ms-python.python:venv"
|
||||
"python-envs.defaultEnvManager": "ms-python.python:venv",
|
||||
"python-envs.pythonProjects": [
|
||||
{
|
||||
"path": "src",
|
||||
"envManager": "ms-python.python:venv",
|
||||
"packageManager": "ms-python.python:pip"
|
||||
},
|
||||
{
|
||||
"path": "src/cli.py",
|
||||
"envManager": "ms-python.python:venv",
|
||||
"packageManager": "ms-python.python:pip"
|
||||
}
|
||||
]
|
||||
}
|
||||
7
main.py
7
main.py
@@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# This is just a main.py as a fallback
|
||||
|
||||
import src.launcher as launcher
|
||||
|
||||
launcher.main()
|
||||
@@ -3,6 +3,7 @@ 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."
|
||||
requires-python = "==3.12.*"
|
||||
|
||||
dependencies = [
|
||||
"pyside6",
|
||||
"requests",
|
||||
@@ -20,13 +21,15 @@ files = [
|
||||
"src/instance_manager.py",
|
||||
"src/launcher.py",
|
||||
"src/system_manager.py",
|
||||
"src/user_data",
|
||||
"src/user_data.py",
|
||||
"src/form.ui",
|
||||
"src/system_info.ui",
|
||||
"src/json_trans.py",
|
||||
"pkg/LCE-Qt-Launcher.desktop",
|
||||
"license.md",
|
||||
"readme.md",
|
||||
"requirements.txt",
|
||||
"src/main.py",
|
||||
"src/cli.py",
|
||||
"res.qrc",
|
||||
"CODE-DE-CONDUITE.md",
|
||||
"code-of-conduct.md",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 32 KiB |
15
src/cli.py
Normal file → Executable file
15
src/cli.py
Normal file → Executable file
@@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from term_image.image import from_file
|
||||
from rich import print
|
||||
|
||||
@@ -31,9 +33,10 @@ buildInfo = BuildInfo()
|
||||
defaultInstance = Instance()
|
||||
instanceManager = InstanceManager(defaultInstance)
|
||||
|
||||
if user_output == "1":
|
||||
instanceManager.play()
|
||||
if user_output == "2":
|
||||
instanceManager.install()
|
||||
else:
|
||||
print("not implemented yet")
|
||||
if __name__ == "__main__":
|
||||
if user_output == "1":
|
||||
instanceManager.play()
|
||||
if user_output == "2":
|
||||
instanceManager.install_instance()
|
||||
else:
|
||||
print("not implemented yet")
|
||||
|
||||
@@ -3,24 +3,26 @@ from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from instance_manager import Instance
|
||||
from build_info import BuildInfo
|
||||
|
||||
from zipfile import ZipFile, BadZipFile, LargeZipFile
|
||||
from io import BytesIO
|
||||
|
||||
import requests
|
||||
import os
|
||||
import stat
|
||||
import platform
|
||||
|
||||
SUCCESS_STATUS_CODE = 200
|
||||
|
||||
class Downloader:
|
||||
def download_client(self, instance : Instance):
|
||||
def __init__(self, build_info: BuildInfo):
|
||||
self._build_info = build_info
|
||||
|
||||
def download_instance(self, instance : Instance):
|
||||
response = requests.get(instance.get_download_url())
|
||||
if response.status_code == SUCCESS_STATUS_CODE:
|
||||
print(f"Download of {instance.name} from {instance.get_download_url} was a success")
|
||||
try:
|
||||
with ZipFile(BytesIO(response.content)) as archive:
|
||||
archive.extractall(instance.installation_path)
|
||||
archive : ZipFile = self.extract_instance(response, instance)
|
||||
except BadZipFile as err:
|
||||
print(f"Error : {err} while extracting {archive.filename}")
|
||||
except LargeZipFile as err:
|
||||
@@ -28,8 +30,11 @@ class Downloader:
|
||||
else:
|
||||
if os.name == "posix":
|
||||
exe_abs_path = os.path.join(instance.installation_path, instance.exe_name)
|
||||
curr_perm = os.stat(exe_abs_path)
|
||||
new_perm = curr_perm.st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH
|
||||
os.chmod(exe_abs_path, new_perm)
|
||||
system = self._build_info.system_manager
|
||||
system.set_file_permission(exe_abs_path)
|
||||
else:
|
||||
print(f"Error : {response.status_code} during the dowbloading of the Minecraft LCE Client")
|
||||
print(f"Error : {response.status_code} during the dowloading of the Minecraft LCE Client")
|
||||
|
||||
def extract_instance(self, response, instance) -> ZipFile:
|
||||
with ZipFile(BytesIO(response.content)) as archive:
|
||||
return archive.extractall(instance.installation_path)
|
||||
@@ -1,15 +1,19 @@
|
||||
from enum import Enum
|
||||
|
||||
from downloader import Downloader
|
||||
from build_info import BuildInfo
|
||||
|
||||
_GITHUB_RELEASE_STR = "/releases/download/"
|
||||
from subprocess import TimeoutExpired
|
||||
|
||||
import subprocess
|
||||
|
||||
_GITHUB_RELEASE_STR = "/releases/download/"
|
||||
|
||||
class InstanceType(Enum):
|
||||
GITHUB_RELEASE = 0
|
||||
GIT_SOURCE_CODE = 1
|
||||
LOCAL_NO_INSTALL = 2
|
||||
REMOTE_GIT_SOURCE = 1
|
||||
LOCAL_INSTALLATION = 2
|
||||
LOCAL_SOURCE_CODE = 3
|
||||
|
||||
class Instance:
|
||||
def __init__(self,
|
||||
@@ -39,18 +43,32 @@ class Instance:
|
||||
_GITHUB_RELEASE_STR + \
|
||||
self.version + "/" + \
|
||||
self.archive_file
|
||||
if self.instance_type == InstanceType.GIT_SOURCE_CODE:
|
||||
if self.instance_type == InstanceType.REMOTE_GIT_SOURCE:
|
||||
return f"{self.repo_url}.git"
|
||||
if self.instance_type == InstanceType.LOCAL_NO_INSTALL:
|
||||
if self.instance_type == InstanceType.LOCAL_INSTALLATION:
|
||||
return RuntimeError("Error ! Ressource Cannot be downloaded. Reason : Ressource is local")
|
||||
else:
|
||||
return RuntimeError("Not implemented yet!")
|
||||
|
||||
class InstanceManager:
|
||||
def __init__(self, instance : Instance):
|
||||
def __init__(self, instance : Instance, build_info : BuildInfo):
|
||||
self.instance = instance
|
||||
self._downloader = Downloader()
|
||||
def play(self):
|
||||
subprocess.run(self.instance.installation_path + self.instance.exe_name)
|
||||
def install(self):
|
||||
self._downloader.download_client(self.instance);
|
||||
self._downloader = Downloader(build_info)
|
||||
self._build_info = build_info
|
||||
def play(self) -> str:
|
||||
try:
|
||||
game_process = subprocess.run(self.instance.installation_path, self.instance.exe_name)
|
||||
except TimeoutExpired as err:
|
||||
print(f"Error : process of lauching instance {self.instance.name} Failed. Reason : Timeout Expired.\n traceback : {err.with_traceback}")
|
||||
return f"Error : process of lauching instance {self.instance.name} Failed. Reason : Timeout Expired.\n traceback : {err.with_traceback}"
|
||||
except PermissionError as err:
|
||||
print(f"Error : Cannot launch {self.instance.name}. Reason : Permission Denied.\n traceback : {err.with_traceback}")
|
||||
return f"Error : Cannot launch {self.instance.name}. Reason : Permission Denied.\n traceback : {err.with_traceback}"
|
||||
|
||||
else:
|
||||
return f"Client closed with code {game_process.returncode}"
|
||||
def install_instance(self) -> str:
|
||||
if self.instance in [InstanceType.GITHUB_RELEASE, InstanceType.REMOTE_GIT_SOURCE]:
|
||||
self._downloader.download_instance(self.instance)
|
||||
else:
|
||||
return "Already Installed, skip installation."
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
from PySide6.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QDialog, QMessageBox
|
||||
from PySide6.QtGui import QPalette, QPixmap, QBrush
|
||||
from PySide6.QtCore import Qt
|
||||
|
||||
from user_pref import UserPref
|
||||
from build_info import BuildInfo
|
||||
@@ -17,7 +18,7 @@ userPref = UserPref()
|
||||
buildInfo = BuildInfo()
|
||||
|
||||
defaultInstance = Instance()
|
||||
instanceManager = InstanceManager(defaultInstance)
|
||||
instanceManager = InstanceManager(defaultInstance, buildInfo)
|
||||
|
||||
BACKGROUND_PIXMAP_IMG = ":/assets/background.png"
|
||||
|
||||
@@ -46,11 +47,15 @@ class launcher(QMainWindow):
|
||||
instanceManager.play()
|
||||
def install(self):
|
||||
print("Starting the installation!")
|
||||
instanceManager.install()
|
||||
instanceManager.install_instance()
|
||||
def show_aboutQt(self):
|
||||
QMessageBox.aboutQt("About Qt")
|
||||
print("Show About Qt popup.")
|
||||
QMessageBox.aboutQt(self, "About Qt")
|
||||
def show_about(self):
|
||||
self.aboutPopupWindow = QDialog()
|
||||
|
||||
self.aboutPopupWindow.setWindowModality(Qt,)
|
||||
|
||||
self.aboutPopupWindow.setWindowTitle(f"About {buildInfo.app_name} {buildInfo.version}")
|
||||
|
||||
imageLabel = QLabel()
|
||||
@@ -89,7 +94,7 @@ class launcher(QMainWindow):
|
||||
|
||||
self.ui.actionAbout.triggered.connect(self.show_about)
|
||||
|
||||
self.ui.actionAbout.triggered.connect(QMessageBox.aboutQt)
|
||||
self.ui.actionAbout_QT.triggered.connect(self.show_aboutQt)
|
||||
|
||||
self.versionlabel = QLabel(f"Version {buildInfo.version}")
|
||||
self.ui.statusbar.addPermanentWidget(self.versionlabel)
|
||||
|
||||
16
src/main.py
Normal file
16
src/main.py
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import launcher
|
||||
import cli
|
||||
|
||||
import sys
|
||||
|
||||
argv = sys.argv
|
||||
|
||||
if len(argv) >= 1:
|
||||
if argv[1] == "cli" :
|
||||
cli.main()
|
||||
else:
|
||||
launcher.main()
|
||||
else:
|
||||
launcher.main()
|
||||
128
src/system_info.ui
Normal file
128
src/system_info.ui
Normal file
@@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>sys_info_dialog</class>
|
||||
<widget class="QDialog" name="sys_info_dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>LCE Qt Launcher - System Info </string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../res.qrc">
|
||||
<normaloff>:/assets/app.ico</normaloff>:/assets/app.ico</iconset>
|
||||
</property>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>30</x>
|
||||
<y>240</y>
|
||||
<width>341</width>
|
||||
<height>32</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QWidget" name="verticalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>20</y>
|
||||
<width>391</width>
|
||||
<height>211</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="appVersion">
|
||||
<property name="text">
|
||||
<string>LCE Qt Launcher V. Unknow</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="qVersionLabel">
|
||||
<property name="text">
|
||||
<string>Qt Version Unknow</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="pyVersionLabel">
|
||||
<property name="text">
|
||||
<string>Python Version Unknow</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="osInfoLabel">
|
||||
<property name="text">
|
||||
<string>Operating System info :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="pluginsInfoLabel">
|
||||
<property name="text">
|
||||
<string>Plugins : </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="runnersLabel">
|
||||
<property name="text">
|
||||
<string>Runners: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../res.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>sys_info_dialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>sys_info_dialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -1,26 +1,43 @@
|
||||
from enum import StrEnum
|
||||
|
||||
import platform
|
||||
import os
|
||||
import stat
|
||||
|
||||
class OperatingSystemType(StrEnum):
|
||||
WINDOWS = "Microsoft Windows",
|
||||
MACOS = "MacOS",
|
||||
LINUX = "GNU/Linux",
|
||||
FREEBSD = "FreeBSD",
|
||||
ANDROID = "Android"
|
||||
ANDROID = "Android",
|
||||
UNKNOWN = "Unknow"
|
||||
|
||||
class SystemManager():
|
||||
def __init__(self):
|
||||
self.type : OperatingSystemType = None
|
||||
self.name : str = None
|
||||
self.version : str = None
|
||||
|
||||
self.determine_os_type()
|
||||
|
||||
def determine_os_type() -> OperatingSystemType :
|
||||
def determine_os_type(self):
|
||||
if (platform.system() == "Linux") :
|
||||
return OperatingSystemType.LINUX
|
||||
self.type = OperatingSystemType.LINUX
|
||||
if (platform.system() == "Darwin") :
|
||||
return OperatingSystemType.MACOS
|
||||
self.type = OperatingSystemType.MACOS
|
||||
if (platform.system() == "Windows") :
|
||||
return OperatingSystemType.WINDOWS
|
||||
self.type = OperatingSystemType.WINDOWS
|
||||
if (platform.system() == "FreeBSD"):
|
||||
self.type = OperatingSystemType.FREEBSD
|
||||
if (platform.system() == "Android") :
|
||||
return OperatingSystemType.WINDOWS
|
||||
self.type = OperatingSystemType.ANDROID
|
||||
else:
|
||||
self.type = OperatingSystemType.UNKNOWN
|
||||
|
||||
def set_file_permission(self, file_abs_path : str) -> str:
|
||||
if self.type in [OperatingSystemType.LINUX, OperatingSystemType.FREEBSD, OperatingSystemType.MACOS]:
|
||||
curr_perm = os.stat(file_abs_path)
|
||||
new_perm = curr_perm.st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH
|
||||
os.chmod(file_abs_path, new_perm)
|
||||
else:
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user