planet/planet/main.py

820 lines
29 KiB
Python
Raw Normal View History

2022-03-14 13:11:34 +00:00
#!/usr/bin/python3
2022-03-02 01:39:02 +00:00
"""
2022-04-11 00:21:59 +00:00
Planet is an improved launcher for Minecraft Pi Edition: Reborn, inspired by gMCPIL, jMCPIL, MCPIL and MCPIL-R.
2022-03-02 01:39:02 +00:00
Copyright (C) 2022 Alexey Pavlov
2022-03-03 02:13:28 +00:00
Copyright (C) 2022 Red-Exe-Engineer
2022-03-19 22:31:09 +00:00
Copyright (C) 2022 Bigjango13
2022-03-02 01:39:02 +00:00
2022-04-15 11:34:38 +00:00
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
2022-03-02 01:39:02 +00:00
2022-04-15 11:34:38 +00:00
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
2022-03-02 01:39:02 +00:00
"""
2022-03-19 13:49:19 +00:00
# Built-in modules import
2022-03-02 01:39:02 +00:00
import sys
2022-03-03 02:13:28 +00:00
import os
import random
from datetime import date
import json
2022-03-12 01:01:30 +00:00
import pathlib
2022-03-02 01:39:02 +00:00
2022-03-19 13:49:19 +00:00
# Define the path used for later
2022-03-14 13:11:34 +00:00
absolute_path = pathlib.Path(__file__).parent.absolute()
2022-03-19 13:49:19 +00:00
# ran only if it's in a deb file
2022-03-14 13:11:34 +00:00
if str(absolute_path).startswith("/usr/bin"):
absolute_path = "/usr/lib/planet-launcher/"
2022-03-19 13:49:19 +00:00
# Make the launcher import local files
2022-03-14 13:11:34 +00:00
sys.path.append(absolute_path)
if os.path.exists("/usr/lib/planet-launcher/"):
sys.path.append("/usr/lib/planet-launcher/")
2022-03-19 13:49:19 +00:00
# Local imports
2022-03-14 13:11:34 +00:00
import launcher
from splashes import SPLASHES
2022-03-24 01:20:58 +00:00
import web
2022-04-08 11:59:20 +00:00
import mcpiedit
2022-03-14 13:11:34 +00:00
2022-03-19 13:49:19 +00:00
# PyQt5 imports
2022-04-03 01:04:39 +00:00
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
2022-04-09 21:40:48 +00:00
from PyQt5.QtWebKit import *
from PyQt5.QtWebKitWidgets import *
2022-03-02 01:39:02 +00:00
2022-04-08 20:07:50 +00:00
from qtwidgets import AnimatedToggle
2022-03-19 13:49:19 +00:00
# Additional imports
import qdarktheme # Dark style for PyQt5
import pypresence # Discord RPC
2022-03-20 17:55:06 +00:00
from PIL import Image
2022-03-20 18:03:17 +00:00
import darkdetect
2022-03-10 00:31:14 +00:00
2022-03-19 13:49:19 +00:00
# Load dark theme
2022-03-12 01:10:07 +00:00
dark_stylesheet = qdarktheme.load_stylesheet()
2022-03-10 00:31:14 +00:00
2022-03-19 13:49:19 +00:00
USER = os.getenv("USER") # Get the username, used for later
2022-03-03 02:13:28 +00:00
2022-03-19 13:49:19 +00:00
# Create the mods directory if it does not exist
2022-03-03 02:13:28 +00:00
if not os.path.exists(f"/home/{USER}/.planet-launcher/mods"):
os.makedirs(f"/home/{USER}/.planet-launcher/mods")
2022-03-24 01:20:58 +00:00
2022-03-20 17:55:06 +00:00
if not os.path.exists(f"/home/{USER}/.minecraft-pi/overrides/images/mob/"):
os.makedirs(f"/home/{USER}/.minecraft-pi/overrides/images/mob/")
2022-03-03 02:13:28 +00:00
2022-03-12 01:14:27 +00:00
# if os.path.exists(f"/home/{USER}/.gmcpil.json"):
# with open(f"/home/{USER}/.gmcpil.json") as f:
# DEFAULT_FEATURES = json.loads(f.read())["features"]
2022-03-12 01:14:27 +00:00
# else:
# TODO: Add a tab with a button to import features from gMCPIL
2022-03-20 18:03:17 +00:00
if darkdetect.isDark():
theme = "dark"
else:
theme = "light"
2022-03-14 13:18:58 +00:00
2022-03-13 01:16:02 +00:00
class ConfigPluto(QDialog):
2022-03-19 13:49:19 +00:00
"""Startup configurator for Planet. Based on QDialog."""
2022-03-13 01:16:02 +00:00
def __init__(self):
super().__init__()
2022-03-19 13:49:19 +00:00
# Remove the window bar
2022-03-13 01:16:02 +00:00
self.setWindowFlag(Qt.FramelessWindowHint)
2022-03-14 13:18:58 +00:00
2022-03-19 13:49:19 +00:00
layout = QVBoxLayout() # Real layout used by the widger
titlelayout = QGridLayout() # Layout for the title
2022-03-14 13:18:58 +00:00
2022-03-19 13:49:19 +00:00
# Load the logo pixmap
2022-03-14 13:18:58 +00:00
logopixmap = QPixmap(f"{absolute_path}/assets/logo512.png").scaled(
100, 100, Qt.KeepAspectRatio
)
2022-03-19 13:49:19 +00:00
# Create the name label
2022-03-13 01:16:02 +00:00
namelabel = QLabel("Pluto Wizard")
2022-03-14 13:18:58 +00:00
2022-03-19 13:49:19 +00:00
logolabel = QLabel() # label used for the logo
logolabel.setPixmap(logopixmap) # Load the pixmap into the label
logolabel.setAlignment(Qt.AlignRight) # Align right
2022-03-14 13:18:58 +00:00
2022-03-19 13:49:19 +00:00
font = namelabel.font() # This font is just used to set the size
2022-03-13 01:16:02 +00:00
font.setPointSize(30)
2022-03-19 13:49:19 +00:00
namelabel.setFont(font) # Apply the font to the label
namelabel.setAlignment(Qt.AlignLeft) # Align left
2022-03-14 13:18:58 +00:00
2022-03-19 13:49:19 +00:00
titlelayout.addWidget(logolabel, 0, 0) # Add the logo into the layout
titlelayout.addWidget(namelabel, 0, 1) # Add the name into the layout
2022-03-13 01:16:02 +00:00
2022-03-19 13:49:19 +00:00
titlewidget = QWidget() # Fake widget that takes the title layout
titlewidget.setLayout(titlelayout) # Set the layout
2022-03-14 13:18:58 +00:00
2022-03-19 13:49:19 +00:00
# Label with information
2022-03-14 13:18:58 +00:00
info_label = QLabel(
'Please select the executable you downloaded.\nIf you installed a DEB, please select the "Link" option'
)
2022-03-19 13:49:19 +00:00
self.executable_btn = QPushButton("Select executable") # Button for AppImage
self.executable_btn.clicked.connect(
self.get_appimage
) # Connect to the function
2022-03-14 13:18:58 +00:00
2022-03-19 13:49:19 +00:00
self.premade_btn = QPushButton(
"Link /usr/bin/minecraft-pi-reborn-client"
) # Button for Pre-installed debs
self.premade_btn.clicked.connect(self.link_appimage) # Connect to the function
2022-03-14 13:18:58 +00:00
2022-03-19 13:49:19 +00:00
self.flatpak_btn = QPushButton("Link flatpak") # Button for linking flatpak
self.flatpak_btn.clicked.connect(self.link_flatpak) # Connect to the function
# Adding things to widgets
2022-03-13 01:16:02 +00:00
layout.addWidget(titlewidget)
layout.addWidget(info_label)
layout.addWidget(self.executable_btn)
2022-03-13 20:46:07 +00:00
layout.addWidget(self.premade_btn)
2022-03-19 00:16:04 +00:00
layout.addWidget(self.flatpak_btn)
2022-03-14 13:18:58 +00:00
2022-03-13 01:16:02 +00:00
self.setLayout(layout)
2022-03-14 13:18:58 +00:00
2022-03-19 13:49:19 +00:00
# Functions below are related to window movement
2022-03-13 01:16:02 +00:00
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.moveFlag = True
self.movePosition = event.globalPos() - self.pos()
self.setCursor(QCursor(Qt.OpenHandCursor))
event.accept()
2022-03-14 13:18:58 +00:00
2022-03-13 01:16:02 +00:00
def mouseMoveEvent(self, event):
if Qt.LeftButton and self.moveFlag:
self.move(event.globalPos() - self.movePosition)
event.accept()
2022-03-14 13:18:58 +00:00
2022-03-13 01:16:02 +00:00
def mouseReleaseEvent(self, event):
self.moveFlag = False
self.setCursor(Qt.ArrowCursor)
2022-03-14 13:18:58 +00:00
2022-03-13 01:16:02 +00:00
def get_appimage(self):
2022-03-19 13:49:19 +00:00
self.hide() # Hide the dialog
# Open the file dialog
2022-03-14 13:18:58 +00:00
self.filename = QFileDialog.getOpenFileName(
self, "Select executable", "/", "Executable files (*.AppImage *.bin *.sh *)"
)
2022-03-13 20:46:07 +00:00
def link_appimage(self):
2022-03-19 13:49:19 +00:00
self.hide() # hide the dialog
# Link the executable with the AppImage
2022-03-14 13:18:58 +00:00
os.symlink(
"/usr/bin/minecraft-pi-reborn-client",
f"/home/{USER}/.planet-launcher/minecraft.AppImage",
)
2022-03-19 13:49:19 +00:00
self.filename = list() # Make a fake list
self.filename.append(
False
) # Append False to the fake list. See end of file for more info
2022-03-19 00:16:04 +00:00
def link_flatpak(self):
2022-04-15 11:34:38 +00:00
script_text = (
"#!/bin/bash\nflatpak run com.thebrokenrail.MCPIReborn $1"
) # Script contents
2022-03-19 13:49:19 +00:00
with open(
f"/home/{USER}/.planet-launcher/minecraft.AppImage", "w"
) as file: # Open the file
file.write(script_text) # Write the script text
self.filename = list() # Fake list. See function above for more info
self.filename.append(False)
2022-03-02 01:39:02 +00:00
2022-03-10 00:31:14 +00:00
2022-03-13 01:16:02 +00:00
class Planet(QMainWindow):
2022-03-19 13:49:19 +00:00
"""Main window class. Contains tabs and everything"""
2022-03-14 13:18:58 +00:00
2022-03-19 13:49:19 +00:00
launchfeatures = dict() # Dictionary for custom features
env = os.environ.copy() # ENV variables
2022-03-10 00:31:14 +00:00
2022-03-02 01:39:02 +00:00
def __init__(self):
super().__init__()
2022-03-22 00:03:20 +00:00
self.center()
2022-03-14 13:18:58 +00:00
try:
2022-03-19 13:49:19 +00:00
RPC = pypresence.Presence(
787496148763541505
) # Try to initialize pypresence and find Discord
RPC.connect() # Connect to Discord
# Set the RPC Status
2022-03-14 13:18:58 +00:00
RPC.update(
state="Launched with Planet Launcher",
details="Minecraft Pi Edition: Reborn",
2022-03-19 13:49:19 +00:00
large_image=random.choice(
["revival", "logo"]
), # Randomly select the logo
small_image=random.choice(
["heart", "portal", "multiplayer", "logo", "revival"]
), # Randomly select the tiny image
2022-03-14 13:18:58 +00:00
)
2022-03-14 01:07:20 +00:00
except:
2022-03-19 13:49:19 +00:00
print(
"Unable to initalize Discord RPC. Skipping."
) # If it fails, e.g Discord is not found, skip. This doesn't matter much.
2022-03-14 13:18:58 +00:00
2022-03-19 13:49:19 +00:00
if not os.path.exists(
f"/home/{USER}/.planet-launcher/config.json"
): # Config file does not exist.
2022-03-14 13:18:58 +00:00
2022-03-19 13:49:19 +00:00
# Set the configuration variable
2022-03-12 23:18:20 +00:00
self.conf = {
2022-03-14 13:18:58 +00:00
"username": "StevePi",
"options": launcher.get_features_dict(
f"/home/{USER}/.planet-launcher/minecraft.AppImage"
),
"hidelauncher": True,
"profile": "Modded MCPE",
"render_distance": "Short",
2022-03-24 01:20:58 +00:00
"theme": theme,
2022-03-14 13:18:58 +00:00
"discord_rpc": True,
2022-04-08 20:07:50 +00:00
"version": "extended_2.3.2",
2022-03-12 23:18:20 +00:00
}
2022-03-14 13:18:58 +00:00
2022-03-19 13:49:19 +00:00
with open(
f"/home/{USER}/.planet-launcher/config.json", "w"
) as file: # Write it to the configuration file
2022-03-12 23:18:20 +00:00
file.write(json.dumps(self.conf))
else:
2022-03-19 13:49:19 +00:00
with open(
f"/home/{USER}/.planet-launcher/config.json"
) as file: # Else, it exists: Read from it.
2022-03-12 23:18:20 +00:00
self.conf = json.loads(file.read())
2022-03-02 01:39:02 +00:00
2022-03-19 13:49:19 +00:00
self.setWindowTitle("Planet") # Set the window title
2022-03-02 01:39:02 +00:00
2022-03-19 13:49:19 +00:00
self.setWindowIcon(
QIcon(f"{absolute_path}/assets/logo512.png")
) # Set the window icon
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
self.widget = QWidget()
self.layout = QStackedLayout()
2022-04-08 20:07:50 +00:00
2022-03-19 13:49:19 +00:00
tabs = QTabWidget() # Create the tabs
2022-03-20 17:55:06 +00:00
tabs.setTabPosition(QTabWidget.North) # Select the tab position.
2022-03-19 13:49:19 +00:00
tabs.setMovable(True) # Allow tab movement.
2022-03-02 01:39:02 +00:00
2022-03-19 13:49:19 +00:00
# Tab part. Please check every function for more info
play_tab = tabs.addTab(self.play_tab(), "Play") # Add the play tab
tabs.setTabIcon(
play_tab, QIcon(f"{absolute_path}/assets/logo512.png")
) # Set the icon for the tab
2022-03-24 01:20:58 +00:00
features_tab = tabs.addTab(
self.features_tab(), "Features"
) # Add the features tab
tabs.setTabIcon(
features_tab, QIcon(f"{absolute_path}/assets/heart512.png")
) # set the icon for the tab
servers_tab = tabs.addTab(self.servers_tab(), "Servers") # Servers tab
2022-03-14 13:18:58 +00:00
tabs.setTabIcon(
2022-03-21 14:56:21 +00:00
servers_tab, QIcon(f"{absolute_path}/assets/portal512.png")
2022-03-24 01:20:58 +00:00
) # Set the icon
2022-03-14 13:18:58 +00:00
# mods_tab = tabs.addTab(self.custom_mods_tab(), "Mods")
# tabs.setTabIcon(mods_tab, QIcon(f"{absolute_path}/assets/portal512.png"))
2022-04-08 11:59:20 +00:00
settings_tab = tabs.addTab(self.settings_tab(), "Settings") # Changelog tab
2022-04-08 20:07:50 +00:00
tabs.setTabIcon(settings_tab, QIcon(f"{absolute_path}/assets/wrench512.png"))
2022-04-08 11:59:20 +00:00
self.layout.addWidget(tabs)
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
self.widget.setLayout(self.layout)
2022-03-02 01:39:02 +00:00
2022-04-08 11:59:20 +00:00
self.setCentralWidget(self.widget) # Set the central widget to the tabs
2022-03-24 01:20:58 +00:00
self.setGeometry(
600, 900, 200, 200
) # Set the window geometry. Doesn't do much effect from my observations, unfortunartely
self.usernameedit.setText(
self.conf["username"]
) # Set the username text to the configuration's variant
self.profilebox.setCurrentText(self.conf["profile"]) # See top comment
self.distancebox.setCurrentText(
self.conf["render_distance"]
) # See top comments
2022-03-14 13:18:58 +00:00
2022-03-13 01:16:02 +00:00
for feature in self.features:
try:
if self.conf["options"][feature]:
2022-03-24 01:20:58 +00:00
self.features[feature].setCheckState(
Qt.Checked
) # Set to checked if the configuration has it to true
else:
2022-03-24 01:20:58 +00:00
self.features[feature].setCheckState(
Qt.Unchecked
) # Else, set it unchecked
except KeyError: # May happen on downgrades or upgrades of the Reborn version
pass
2022-03-24 01:20:58 +00:00
2022-03-19 13:49:19 +00:00
# Hide launcher/Show it depending on the config
2022-03-13 01:16:02 +00:00
self.showlauncher.setChecked(self.conf["hidelauncher"])
2022-03-24 01:20:58 +00:00
2022-03-19 13:49:19 +00:00
# Set the features
2022-03-10 00:31:14 +00:00
self.set_features()
2022-03-02 01:39:02 +00:00
def play_tab(self) -> QWidget:
2022-03-19 13:49:19 +00:00
"""The main tab, with the main functionality"""
2022-03-24 01:20:58 +00:00
layout = QGridLayout() # The layout
titlelayout = QGridLayout() # The layout for the title
2022-03-12 01:14:27 +00:00
2022-03-19 13:49:19 +00:00
# Load the logo pixmap
2022-03-14 13:18:58 +00:00
logopixmap = QPixmap(f"{absolute_path}/assets/logo512.png").scaled(
2022-03-24 01:20:58 +00:00
100, 100, Qt.KeepAspectRatio # Scale it, but keep the aspect ratio
2022-03-14 13:18:58 +00:00
)
2022-03-12 01:14:27 +00:00
2022-03-24 01:20:58 +00:00
logolabel = QLabel() # Label for the pixmap
logolabel.setPixmap(logopixmap) # apply the pixmap onto the label
logolabel.setAlignment(Qt.AlignRight) # Align the label
namelabel = QLabel() # Label for the title
2022-03-10 00:31:14 +00:00
2022-03-19 13:49:19 +00:00
# Ester eggs
2022-03-12 01:14:27 +00:00
if date.today().month == 4 and date.today().day == 1:
2022-03-24 01:20:58 +00:00
namelabel.setText(
"Banana Launcher"
) # If the date is april fish, show the banana easter egg
else:
2022-03-12 01:14:27 +00:00
if random.randint(1, 100) == 1:
2022-03-24 01:20:58 +00:00
namelabel.setText("Pluto Launcher") # a 1/100, Pluto launcher
else:
2022-03-24 01:20:58 +00:00
namelabel.setText("Planet Launcher") # Else, just set it normal
2022-03-10 00:31:14 +00:00
2022-03-24 01:20:58 +00:00
font = namelabel.font() # Font used
font.setPointSize(30) # Set the font size
namelabel.setFont(font) # Aplly the font onto the label
namelabel.setAlignment(Qt.AlignLeft) # Align the label
2022-03-10 00:31:14 +00:00
2022-03-24 01:20:58 +00:00
splashlabel = QLabel(
f'<font color="gold">{random.choice(SPLASHES)}</font>'
) # Label for splash. Uses QSS for color
splashlabel.adjustSize() # Adjust the size just in case
splashlabel.setAlignment(Qt.AlignHCenter) # Align the label
2022-03-02 01:39:02 +00:00
2022-03-24 01:20:58 +00:00
usernamelabel = QLabel("Username") # Label that is used to direct the line edit
2022-03-02 01:39:02 +00:00
2022-03-24 01:20:58 +00:00
self.usernameedit = QLineEdit() # Line Edit for username
self.usernameedit.setPlaceholderText("StevePi") # Set ghost value
2022-03-02 01:39:02 +00:00
2022-03-24 01:20:58 +00:00
distancelabel = QLabel(
"Render Distance"
) # Label that is used to direct the combo box
2022-03-02 01:39:02 +00:00
2022-03-24 01:20:58 +00:00
self.distancebox = QComboBox()
self.distancebox.addItems(["Far", "Normal", "Short", "Tiny"]) # Set the values
self.distancebox.setCurrentText("Short") # Set the default option
2022-03-02 01:39:02 +00:00
2022-03-24 01:20:58 +00:00
profilelabel = QLabel("Profile") # Label that is used to direct the combo box
2022-03-02 01:39:02 +00:00
2022-03-24 01:20:58 +00:00
self.profilebox = QComboBox()
2022-03-02 01:39:02 +00:00
self.profilebox.addItems(
2022-03-24 01:20:58 +00:00
[
"Vanilla MCPi",
"Modded MCPi",
"Modded MCPE",
"Optimized MCPE",
"Custom",
] # Add items into the combo box
2022-03-02 01:39:02 +00:00
)
2022-03-24 01:20:58 +00:00
self.profilebox.setCurrentText("Modded MCPE") # Set the current selection
self.showlauncher = QRadioButton(
"Hide Launcher"
) # RadioButton used for hiding the launcher
2022-03-02 01:39:02 +00:00
2022-03-24 01:20:58 +00:00
self.versionbox = QComboBox()
2022-03-26 00:59:39 +00:00
2022-04-08 20:07:50 +00:00
# versions = json.loads(web.get_versions())["versions"]
2022-03-26 00:59:39 +00:00
2022-04-08 20:07:50 +00:00
# version_list = list()
2022-03-26 00:59:39 +00:00
2022-04-08 20:07:50 +00:00
# for version in versions:
# version_list.append(versions[version])
2022-03-26 00:59:39 +00:00
2022-04-08 20:07:50 +00:00
# version_name_list = list()
2022-03-26 00:59:39 +00:00
2022-04-08 20:07:50 +00:00
# for version in version_list:
# version_name_list.append(version["name"])
2022-03-26 00:59:39 +00:00
2022-04-08 20:07:50 +00:00
# self.versionbox.addItems(version_name_list) # Set the values
# self.versionbox.setCurrentText("Short") # Set the default option
2022-03-10 00:31:14 +00:00
2022-03-24 01:20:58 +00:00
self.playbutton = QPushButton("Play") # The most powerful button
self.playbutton.setCheckable(True) # Allow checking it
self.playbutton.clicked.connect(
self.launch
) # Connect it to the executing function
2022-03-02 01:39:02 +00:00
2022-03-19 22:31:09 +00:00
# Add widgets into the title layout
2022-03-10 00:31:14 +00:00
titlelayout.addWidget(logolabel, 0, 0)
titlelayout.addWidget(namelabel, 0, 1)
2022-03-12 01:14:27 +00:00
2022-03-10 00:31:14 +00:00
titlewidget = QWidget()
2022-03-24 01:20:58 +00:00
titlewidget.setLayout(titlelayout) # Apply the layout onto a fake widget
layout.addWidget(
titlewidget, 0, 0, 2, 5
) # Apply that widget onto the main layout
2022-03-12 01:14:27 +00:00
2022-03-19 22:31:09 +00:00
# All other widgets are applied here
2022-03-12 01:14:27 +00:00
layout.addWidget(splashlabel, 2, 0, 1, 6)
2022-03-02 01:39:02 +00:00
layout.addWidget(usernamelabel, 3, 0)
layout.addWidget(self.usernameedit, 3, 4, 1, 2)
2022-03-02 01:39:02 +00:00
layout.addWidget(distancelabel, 4, 0)
layout.addWidget(self.distancebox, 4, 4, 1, 2)
2022-03-02 01:39:02 +00:00
layout.addWidget(profilelabel, 5, 0)
layout.addWidget(self.profilebox, 5, 4, 1, 2)
2022-03-20 17:55:06 +00:00
layout.addWidget(self.showlauncher, 6, 4)
2022-03-24 01:20:58 +00:00
2022-04-08 20:07:50 +00:00
# layout.addWidget(self.versionbox, 8, 0, 1, 3)
2022-03-02 01:39:02 +00:00
2022-03-24 01:20:58 +00:00
layout.addWidget(self.playbutton, 8, 4, 1, 2)
2022-03-02 01:39:02 +00:00
widget = QWidget()
2022-03-24 01:20:58 +00:00
widget.setLayout(layout) # Apply the layout onto the main widget
2022-03-02 01:39:02 +00:00
return widget
2022-03-03 00:55:02 +00:00
def features_tab(self) -> QWidget:
2022-03-03 00:55:02 +00:00
layout = QVBoxLayout()
2022-03-10 00:31:14 +00:00
2022-03-24 01:20:58 +00:00
self.features = dict() # Dictionary used for storing checkboxes for features
default_features = launcher.get_features_dict( # Get default feature list
2022-03-14 13:18:58 +00:00
f"/home/{USER}/.planet-launcher/minecraft.AppImage"
)
2022-03-24 01:20:58 +00:00
for feature in default_features: # Loop in default features
checkbox = QCheckBox(feature) # For each feature, create a checkbox
2022-03-19 22:31:09 +00:00
# TODO: Fix the error if newer features are added here, or check for them in self.conf
2022-03-24 01:20:58 +00:00
if default_features[feature]: # Check if it's checked. If so, check it
2022-03-03 00:55:02 +00:00
checkbox.setCheckState(Qt.Checked)
else:
checkbox.setCheckState(Qt.Unchecked)
2022-03-10 00:31:14 +00:00
2022-03-24 01:20:58 +00:00
checkbox.clicked.connect(self.set_features) # Connect saving function
2022-03-10 00:31:14 +00:00
2022-03-24 01:20:58 +00:00
self.features[feature] = checkbox # Add the checkbox into the list
2022-03-24 01:20:58 +00:00
layout.addWidget(checkbox) # Add the checkbox into the layout
2022-03-24 01:20:58 +00:00
fakewidget = QWidget() # Create a fake widget to apply the layout on
fakewidget.setLayout(layout) # Apply the layoutonto
2022-03-24 01:20:58 +00:00
scroll = QScrollArea() # Add a scoll area
2022-03-24 01:20:58 +00:00
scroll.setVerticalScrollBarPolicy(
Qt.ScrollBarAlwaysOn
) # Shoe the vertical scroll bar
scroll.setHorizontalScrollBarPolicy(
Qt.ScrollBarAlwaysOff
) # Hide the horizontak scroll bar
scroll.setWidgetResizable(
True
) # Allow window resizing and fix itt with the scrollbar
scroll.setWidget(fakewidget) # Set the main widget into the scrollbar
2022-03-03 00:55:02 +00:00
fakelayout = QGridLayout()
2022-03-24 01:20:58 +00:00
fakelayout.addWidget(scroll, 0, 0) # Apply the scrollbar onto the layout
2022-03-03 00:55:02 +00:00
2022-03-03 02:13:28 +00:00
widget = QWidget()
widget.setLayout(fakelayout)
return widget
2022-03-14 13:18:58 +00:00
def servers_tab(self) -> QWidget:
widget = QWidget()
layout = QGridLayout()
2022-03-24 01:20:58 +00:00
self.serversedit = QTextEdit() # Create a text editing area
2022-03-20 17:55:06 +00:00
if not os.path.exists(f"/home/{USER}/.minecraft-pi/servers.txt"):
with open(f"/home/{USER}/.minecraft-pi/servers.txt") as servers:
servers.write("pbptanarchy.tk")
2022-03-24 01:20:58 +00:00
self.serversedit.textChanged.connect(
self.save_servers
) # Connect on change to the save function
with open(f"/home/{USER}/.minecraft-pi/servers.txt") as servers:
2022-03-24 01:20:58 +00:00
self.serversedit.setPlainText(
servers.read()
) # Set the text of the text editing area
2022-03-24 01:20:58 +00:00
infolabel = QLabel( # Label with information about the server format
2022-03-14 13:18:58 +00:00
'Servers are stored in the format of <font color="gold">IP: </font><font color="blue">Port</font>'
)
2022-03-24 01:20:58 +00:00
layout.addWidget(self.serversedit, 0, 0) # Add the widgets
2022-03-14 13:18:58 +00:00
layout.addWidget(infolabel, 6, 0)
widget.setLayout(layout)
return widget
2022-03-03 02:13:28 +00:00
def custom_mods_tab(self) -> QWidget:
layout = QVBoxLayout()
2022-03-24 01:20:58 +00:00
for mod in os.listdir(
f"/home/{USER}/.planet-launcher/mods/"
): # Loop in every mod in the mod directory
checkbox = QCheckBox(mod) # Create a checkbox with the mod name
checkbox.setCheckState(Qt.Unchecked) # Set it to unchecked
2022-03-03 02:13:28 +00:00
layout.addWidget(checkbox)
2022-03-03 02:13:28 +00:00
fakewidget = QWidget()
fakewidget.setLayout(layout)
2022-03-03 02:13:28 +00:00
scroll = QScrollArea()
2022-03-03 02:13:28 +00:00
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll.setWidgetResizable(True)
scroll.setWidget(fakewidget)
2022-03-03 02:13:28 +00:00
fakelayout = QGridLayout()
fakelayout.addWidget(scroll, 0, 0)
2022-03-03 02:13:28 +00:00
2022-03-03 00:55:02 +00:00
widget = QWidget()
widget.setLayout(fakelayout)
return widget
2022-03-12 01:14:27 +00:00
2022-04-08 11:59:20 +00:00
def changelog_widget(self):
2022-04-09 21:40:48 +00:00
web_engine = QWebView() # Create a webview object
2022-04-08 11:59:20 +00:00
web_engine.load(
2022-03-24 01:20:58 +00:00
QUrl().fromLocalFile(f"{absolute_path}/assets/changelog.html")
) # Load the local file
2022-03-19 22:31:09 +00:00
# TODO: Use two different tabs for the webview
2022-03-13 01:16:02 +00:00
2022-04-08 11:59:20 +00:00
return web_engine
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
def settings_widget(self):
widget = QWidget()
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
layout = QGridLayout()
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
skin_label = QLabel("Set the skin")
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
self.skin_button = QPushButton("Select Skin")
self.skin_button.clicked.connect(self.select_skin)
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
config_label = QLabel("Reset config")
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
self.delete_config_button = QPushButton("Delete config")
self.delete_config_button.clicked.connect(self.delete_config)
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
appimage_label = QLabel("Delete executable")
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
self.delete_appimage_button = QPushButton("Delete")
self.delete_appimage_button.clicked.connect(self.delete_appimage)
2022-04-11 00:21:59 +00:00
2022-04-14 01:16:27 +00:00
self.import_gmcpil_button = QPushButton("Import settings")
self.import_gmcpil_button.clicked.connect(self.import_gmcpil)
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
layout.addWidget(skin_label, 0, 0)
layout.addWidget(self.skin_button, 0, 1)
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
layout.addWidget(config_label, 1, 0)
2022-04-08 20:07:50 +00:00
layout.addWidget(self.delete_config_button, 1, 1)
2022-04-08 11:59:20 +00:00
layout.addWidget(appimage_label, 2, 0)
2022-04-08 20:07:50 +00:00
layout.addWidget(self.delete_appimage_button, 2, 1)
2022-04-08 11:59:20 +00:00
widget.setLayout(layout)
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
return widget
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
def settings_tab(self):
tabs = QTabWidget()
tabs.setTabPosition(QTabWidget.South)
2022-04-08 20:07:50 +00:00
settings_tab = tabs.addTab(self.settings_widget(), "General")
changelog_tab = tabs.addTab(self.changelog_widget(), "Changelog")
editor_tab = tabs.addTab(mcpiedit.NBTEditor(), "MCPIEdit")
2022-04-08 11:59:20 +00:00
tabs.setTabIcon(
settings_tab, QIcon(f"{absolute_path}/assets/wrench512.png")
) # Set the icon
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
tabs.setTabIcon(
changelog_tab, QIcon(f"{absolute_path}/assets/git.png")
) # Set the icon
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
tabs.setTabIcon(
editor_tab, QIcon(f"{absolute_path}/assets/mcpiedit.png")
) # Set the icon
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
return tabs
2022-04-14 01:16:27 +00:00
2022-04-11 00:21:59 +00:00
def import_gmcpil(self):
with open(f"/home/{USER}/.gmcpil.json") as f:
gmcpil_features = json.loads(f.read())["features"]
for feature in gmcpil_features:
try:
if gmcpil_features[feature]:
self.features[feature].setCheckState(
Qt.Checked
) # Set to checked if the configuration has it to true
self.conf["options"][feature] = True
else:
self.features[feature].setCheckState(
Qt.Unchecked
) # Else, set it unchecked
self.conf["options"][feature] = False
except KeyError: # May happen on downgrades or upgrades of the Reborn version
pass
2022-03-14 14:06:57 +00:00
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.moveFlag = True
self.movePosition = event.globalPos() - self.pos()
self.setCursor(QCursor(Qt.OpenHandCursor))
event.accept()
def mouseMoveEvent(self, event):
if Qt.LeftButton and self.moveFlag:
self.move(event.globalPos() - self.movePosition)
event.accept()
def mouseReleaseEvent(self, event):
self.moveFlag = False
self.setCursor(Qt.ArrowCursor)
2022-03-24 01:20:58 +00:00
2022-03-22 00:03:20 +00:00
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
2022-03-10 00:31:14 +00:00
2022-03-05 00:43:14 +00:00
def set_features(self):
for feature in self.features:
if self.features[feature].isChecked():
self.launchfeatures[feature] = True
else:
self.launchfeatures[feature] = False
2022-03-14 13:18:58 +00:00
2022-03-13 01:16:02 +00:00
def save_profile(self):
2022-03-19 22:31:09 +00:00
self.set_features()
2022-03-13 01:16:02 +00:00
self.conf["username"] = self.usernameedit.text()
self.conf["options"] = self.launchfeatures
self.conf["render_distance"] = self.distancebox.currentText()
2022-03-20 18:27:43 +00:00
self.conf["profile"] = self.profilebox.currentText()
2022-03-13 01:16:02 +00:00
self.conf["hidelauncher"] = self.showlauncher.isChecked()
2022-03-14 13:18:58 +00:00
with open(f"/home/{USER}/.planet-launcher/config.json", "w") as file:
file.write(json.dumps(self.conf))
def save_servers(self):
2022-03-14 13:18:58 +00:00
with open(f"/home/{USER}/.minecraft-pi/servers.txt", "w") as file:
file.write(self.serversedit.toPlainText())
2022-03-24 01:20:58 +00:00
2022-03-20 17:55:06 +00:00
def select_skin(self):
filename = QFileDialog.getOpenFileName(
self, "Select skin file", "/", "PNG files (*.png)"
)
2022-03-24 01:20:58 +00:00
if not filename == "":
with open(
f"/home/{USER}/.minecraft-pi/overrides/images/mob/char.png", "w"
) as skin:
skin.write("quick placeholder")
2022-03-24 01:20:58 +00:00
Image.open(filename[0]).crop((0, 0, 64, 32)).convert("RGBA").save(
f"/home/{USER}/.minecraft-pi/overrides/images/mob/char.png"
)
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
def delete_config(self):
2022-04-09 01:07:36 +00:00
dialog = QMessageBox()
dialog.setWindowTitle("Are you sure you want to reset?")
2022-04-14 01:16:27 +00:00
dialog.setText(
"Are you sure you want to delete the config? This action is unrecoverable."
)
2022-04-09 01:07:36 +00:00
dialog.setStandardButtons(QMessageBox.Ok | QMessageBox.Abort)
dialog.setIcon(QMessageBox.Warning)
2022-04-14 01:16:27 +00:00
2022-04-09 01:07:36 +00:00
button = dialog.exec()
2022-04-14 01:16:27 +00:00
2022-04-09 01:07:36 +00:00
if button == QMessageBox.Ok:
2022-04-14 01:16:27 +00:00
2022-04-09 01:07:36 +00:00
os.remove(f"/home/{USER}/.planet-launcher/config.json")
self.hide()
sys.exit()
2022-04-08 20:07:50 +00:00
2022-04-08 11:59:20 +00:00
def delete_appimage(self):
2022-04-09 01:07:36 +00:00
dialog = QMessageBox()
dialog.setWindowTitle("Are you sure you want to reset?")
2022-04-14 01:16:27 +00:00
dialog.setText(
"Are you sure you want to delete the AppImage? This action is unrecoverable."
)
2022-04-09 01:07:36 +00:00
dialog.setStandardButtons(QMessageBox.Ok | QMessageBox.Abort)
dialog.setIcon(QMessageBox.Warning)
2022-04-14 01:16:27 +00:00
2022-04-09 01:07:36 +00:00
button = dialog.exec()
2022-04-14 01:16:27 +00:00
2022-04-09 01:07:36 +00:00
if button == QMessageBox.Ok:
2022-04-14 01:16:27 +00:00
2022-04-09 01:07:36 +00:00
os.remove(f"/home/{USER}/.planet-launcher/minecraft.AppImage")
self.hide()
sys.exit()
2022-03-10 00:31:14 +00:00
2022-03-05 00:43:14 +00:00
def launch(self):
2022-03-13 01:16:02 +00:00
self.save_profile()
2022-03-24 01:20:58 +00:00
2022-03-20 18:27:43 +00:00
if self.profilebox.currentText().lower() == "vanilla mcpi":
2022-03-24 01:20:58 +00:00
self.launchfeatures = launcher.get_features_dict(
f"/home/{USER}/.planet-launcher/minecraft.AppImage"
)
2022-03-20 18:27:43 +00:00
for feature in self.launchfeatures:
self.launchfeatures[feature] = False
elif self.profilebox.currentText().lower() == "modded mcpi":
2022-03-24 01:20:58 +00:00
self.launchfeatures = launcher.get_features_dict(
f"/home/{USER}/.planet-launcher/minecraft.AppImage"
)
2022-03-20 18:27:43 +00:00
self.launchfeatures["Touch GUI"] = False
elif self.profilebox.currentText().lower() == "modded mcpe":
2022-03-24 01:20:58 +00:00
self.launchfeatures = launcher.get_features_dict(
f"/home/{USER}/.planet-launcher/minecraft.AppImage"
)
2022-03-20 18:27:43 +00:00
elif self.profilebox.currentText().lower() == "optimized mcpe":
2022-03-24 01:20:58 +00:00
self.launchfeatures = launcher.get_features_dict(
f"/home/{USER}/.planet-launcher/minecraft.AppImage"
)
2022-03-20 18:27:43 +00:00
self.launchfeatures["Fancy Graphics"] = False
self.launchfeatures["Smooth Lightning"] = False
self.launchfeatures["Animated Water"] = False
self.launchfeatures['Disable "gui_blocks" Atlas'] = False
2022-03-24 01:20:58 +00:00
2022-03-12 01:14:27 +00:00
self.env = launcher.set_username(self.env, self.usernameedit.text())
self.env = launcher.set_options(self.env, self.launchfeatures)
self.env = launcher.set_render_distance(
self.env, self.distancebox.currentText()
)
2022-03-10 00:31:14 +00:00
if self.showlauncher.isChecked() == True:
2022-03-12 18:48:28 +00:00
self.hide()
2022-03-14 13:18:58 +00:00
launcher.run(
self.env, f"/home/{USER}/.planet-launcher/minecraft.AppImage"
).wait()
else:
launcher.run(self.env, f"/home/{USER}/.planet-launcher/minecraft.AppImage")
2022-03-12 01:30:19 +00:00
self.show()
2022-03-02 01:39:02 +00:00
if __name__ == "__main__":
2022-03-14 13:18:58 +00:00
2022-03-13 01:16:02 +00:00
apppath = str()
2022-03-14 13:18:58 +00:00
2022-03-02 01:39:02 +00:00
app = QApplication(sys.argv)
2022-03-20 17:55:06 +00:00
if os.path.exists(f"/home/{USER}/.planet-launcher/config.json"):
with open(f"/home/{USER}/.planet-launcher/config.json") as file:
app.setPalette(qdarktheme.load_palette(json.loads(file.read())["theme"]))
2022-03-20 18:03:17 +00:00
else:
app.setPalette(qdarktheme.load_palette(theme))
2022-03-24 01:20:58 +00:00
2022-03-13 02:02:43 +00:00
if not os.path.exists(f"/home/{USER}/.planet-launcher/minecraft.AppImage"):
2022-03-13 01:16:02 +00:00
pluto = ConfigPluto()
pluto.show()
pluto.exec()
2022-03-14 13:18:58 +00:00
if pluto.filename[0] == "":
2022-03-13 20:46:07 +00:00
sys.exit(-1)
elif pluto.filename[0] == False:
print("Using /usr/bin as an executable.")
else:
2022-03-14 13:18:58 +00:00
with open(pluto.filename[0], "rb") as appimage:
with open(
f"/home/{USER}/.planet-launcher/minecraft.AppImage", "wb"
) as out:
2022-03-13 20:46:07 +00:00
out.write(appimage.read())
2022-03-14 13:41:42 +00:00
os.chmod(f"/home/{USER}/.planet-launcher/minecraft.AppImage", 0o755)
2022-03-14 13:18:58 +00:00
2022-03-02 01:39:02 +00:00
window = Planet()
window.show()
2022-03-14 13:18:58 +00:00
2022-03-02 01:39:02 +00:00
app.exec()