Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import subprocess
- import sys
- import importlib.metadata
- import tkinter as tk
- from tkinter import ttk, messagebox, scrolledtext
- import requests
- import os
- import json
- import threading
- import re
- import hashlib
- import pyperclip
- import zipfile
- from datetime import datetime
- import platform
- import webbrowser
- from packaging import version as pkg_version
- import humanize
- from colorama import init, Fore, Style
- from PIL import Image, ImageTk
- # Inicjalizacja colorama
- init(autoreset=True)
- # Instalacja zależności
- def install_requirements():
- required_libraries = ['requests', 'pyperclip', 'packaging', 'humanize', 'colorama', 'pillow']
- for library in required_libraries:
- try:
- importlib.metadata.version(library)
- print(f"{Fore.LIGHTCYAN_EX}{Fore.GREEN}[OK] {library} już zainstalowane.")
- except importlib.metadata.PackageNotFoundError:
- try:
- subprocess.check_call([sys.executable, "-m", "pip", "install", library])
- print(f"{Fore.LIGHTCYAN_EX}{Fore.CYAN}[INFO] {library} zainstalowane.")
- except subprocess.CalledProcessError:
- print(f"{Fore.LIGHTCYAN_EX}{Fore.RED}[ERROR] Nie udało się zainstalować {library}.")
- install_requirements()
- # Ścieżki
- BASE_DIR = os.path.join(os.getcwd(), "minecraft")
- CONFIG_FILE = os.path.join(BASE_DIR, "config.json")
- ASSETS_DIR = os.path.join(BASE_DIR, "assets")
- LIBRARIES_DIR = os.path.join(BASE_DIR, "libraries")
- NATIVES_DIR = os.path.join(BASE_DIR, "natives")
- LOGS_DIR = os.path.join(BASE_DIR, "logs")
- JAVA_DIR = os.path.join(BASE_DIR, "java")
- ICONS_DIR = os.path.join(BASE_DIR, "icons")
- # Kolory i styl
- BG_COLOR = "#1a1a1a"
- FG_COLOR = "#ffffff"
- ACCENT_COLOR = "#2a9fd6"
- CONSOLE_BG = "#0d0d0d"
- CONSOLE_FG = "#00ff00"
- BUTTON_BG = "#333333"
- BUTTON_HOVER = "#555555"
- SIDEBAR_BG = "#222222"
- ACTIVE_TAB_COLOR = "#1e6f9f"
- HOVER_TAB_COLOR = "#3a3a3a"
- # Globalne zmienne
- pending_instance_settings = {}
- pending_version = ""
- download_thread = None
- download_active = False
- global_progress_bar = None
- global_status_label = None
- instances = {} # Globalna zmienna dla instancji
- java_versions_cache = {} # Globalna zmienna dla wersji Javy
- console = None # Globalna zmienna dla konsoli
- # Funkcje narzędziowe
- def log_to_console(console, message, level="INFO"):
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- try:
- console.config(state="normal")
- if level == "ERROR":
- console.tag_config("error", foreground="red")
- console.insert(tk.END, f"[{timestamp}] {level}: {message}\n", "error")
- elif level == "WARNING":
- console.tag_config("warning", foreground="yellow")
- console.insert(tk.END, f"[{timestamp}] {level}: {message}\n", "warning")
- elif level == "SUCCESS":
- console.tag_config("success", foreground="green")
- console.insert(tk.END, f"[{timestamp}] {level}: {message}\n", "success")
- else:
- console.insert(tk.END, f"[{timestamp}] {level}: {message}\n")
- console.see(tk.END)
- console.config(state="disabled")
- except:
- os.makedirs(LOGS_DIR, exist_ok=True)
- with open(os.path.join(LOGS_DIR, "error.log"), "a", encoding="utf-8") as f:
- f.write(f"[{timestamp}] {level}: {message}\n")
- def verify_sha1(file_path, expected_sha1):
- sha1 = hashlib.sha1()
- with open(file_path, "rb") as f:
- for chunk in iter(lambda: f.read(4096), b""):
- sha1.update(chunk)
- return sha1.hexdigest() == expected_sha1
- def save_config():
- config = {
- "default_settings": {
- "username": username_var.get(),
- "memory": memory_var.get(),
- "shared_assets": shared_assets_var.get(),
- "shared_libraries": shared_libraries_var.get(),
- "shared_natives": shared_natives_var.get()
- },
- "version_filters": {
- "snapshots": snapshots_var.get(),
- "releases": releases_var.get(),
- "alpha": alpha_var.get(),
- "beta": beta_var.get()
- },
- "instances": instances,
- "java_versions": java_versions_cache
- }
- os.makedirs(BASE_DIR, exist_ok=True)
- with open(CONFIG_FILE, "w", encoding="utf-8") as f:
- json.dump(config, f, indent=4)
- def load_config():
- global instances, java_versions_cache, username_var, memory_var, shared_assets_var, shared_libraries_var, shared_natives_var, snapshots_var, releases_var, alpha_var, beta_var
- if os.path.exists(CONFIG_FILE):
- try:
- with open(CONFIG_FILE, "r", encoding="utf-8") as f:
- config = json.load(f)
- # Aktualizuj globalne zmienne zamiast tworzyć nowe
- if "default_settings" in config:
- default_settings = config["default_settings"]
- username_var.set(default_settings.get("username", "Player"))
- memory_var.set(default_settings.get("memory", "2"))
- shared_assets_var.set(default_settings.get("shared_assets", True))
- shared_libraries_var.set(default_settings.get("shared_libraries", True))
- shared_natives_var.set(default_settings.get("shared_natives", True))
- if "version_filters" in config:
- version_filters = config["version_filters"]
- snapshots_var.set(version_filters.get("snapshots", True))
- releases_var.set(version_filters.get("releases", True))
- alpha_var.set(version_filters.get("alpha", False))
- beta_var.set(version_filters.get("beta", False))
- if "instances" in config:
- instances = config["instances"]
- if "java_versions" in config:
- java_versions_cache = config["java_versions"]
- return instances, java_versions_cache
- except Exception as e:
- log_to_console(console, f"Błąd wczytywania konfiguracji: {e}", "ERROR")
- # Przywróć domyślne wartości w przypadku błędu
- instances = {}
- java_versions_cache = {}
- return instances, java_versions_cache
- # Domyślne wartości jeśli plik nie istnieje
- instances = {}
- java_versions_cache = {}
- return instances, java_versions_cache
- def get_versions():
- try:
- url = "https://launchermeta.mojang.com/mc/game/version_manifest.json"
- resp = requests.get(url, timeout=10)
- resp.raise_for_status()
- manifest = resp.json()
- versions = []
- allowed_types = []
- if snapshots_var.get():
- allowed_types.append("snapshot")
- if releases_var.get():
- allowed_types.append("release")
- if alpha_var.get():
- allowed_types.append("old_alpha")
- if beta_var.get():
- allowed_types.append("old_beta")
- for v in manifest["versions"]:
- if v["type"] in allowed_types:
- versions.append(v["id"])
- log_to_console(None, f"Pobrano {len(versions)} wersji (filtry: {allowed_types})", "INFO")
- return sorted(versions, key=lambda x: x, reverse=True)
- except Exception as e:
- log_to_console(None, f"Nie udało się pobrać wersji: {e}", "ERROR")
- return []
- def get_version_info(version):
- try:
- url = "https://launchermeta.mojang.com/mc/game/version_manifest.json"
- resp = requests.get(url, timeout=10)
- resp.raise_for_status()
- manifest = resp.json()
- for v in manifest["versions"]:
- if v["id"] == version:
- version_url = v["url"]
- return requests.get(version_url, timeout=10).json()
- return None
- except Exception as e:
- log_to_console(None, f"Nie udało się pobrać info o wersji: {e}", "ERROR")
- return None
- def download_java(java_version, console):
- try:
- system = platform.system().lower()
- arch = "x64"
- base_url = "https://api.adoptium.net/v3/binary/latest/"
- java_map = {
- "1.8": "8",
- "16": "16",
- "17": "17",
- "21": "21"
- }
- feature_version = java_map.get(java_version, java_version)
- url = f"{base_url}{feature_version}/ga/{system}/{arch}/jdk/hotspot/normal/eclipse"
- log_to_console(console, f"Pobieranie Javy {java_version} z {url}", "INFO")
- resp = requests.get(url, stream=True, timeout=10)
- resp.raise_for_status()
- total_size = int(resp.headers.get('content-length', 0))
- java_dir = os.path.join(JAVA_DIR, f"jdk-{feature_version}")
- os.makedirs(java_dir, exist_ok=True)
- zip_path = os.path.join(java_dir, f"jdk-{feature_version}.zip")
- downloaded_size = 0
- with open(zip_path, "wb") as f:
- for chunk in resp.iter_content(chunk_size=8192):
- if chunk:
- f.write(chunk)
- downloaded_size += len(chunk)
- if total_size > 0 and global_progress_bar:
- update_progress(global_progress_bar, global_status_label,
- (downloaded_size/total_size)*100, total_size-downloaded_size, "java", 1, 1)
- log_to_console(console, f"Rozpakowywanie Javy do {java_dir}", "INFO")
- with zipfile.ZipFile(zip_path, 'r') as zip_ref:
- zip_ref.extractall(java_dir)
- os.remove(zip_path)
- for root, _, files in os.walk(java_dir):
- if "java.exe" in files:
- java_path = os.path.join(root, "java.exe")
- version = get_java_version(java_path)
- if version:
- log_to_console(console, f"Pobrano Javę: {java_path} (wersja: {version})", "SUCCESS")
- return java_path, version
- log_to_console(console, "Nie znaleziono java.exe w pobranym archiwum!", "ERROR")
- return None, None
- except Exception as e:
- log_to_console(console, f"Błąd pobierania Javy {java_version}: {e}", "ERROR")
- return None, None
- def find_java(required_version=None):
- possible_paths = []
- log_to_console(None, f"Szukam Javy {required_version or 'dowolnej'}...", "INFO")
- if os.path.exists(JAVA_DIR):
- for java_folder in os.listdir(JAVA_DIR):
- java_path = os.path.join(JAVA_DIR, java_folder, "bin", "java.exe")
- if os.path.exists(java_path):
- version = get_java_version(java_path)
- if version and (not required_version or check_java_version(version, required_version)):
- possible_paths.append((java_path, version))
- log_to_console(None, f"Znaleziono Javę w {java_path} (wersja: {version})", "INFO")
- java_home = os.environ.get("JAVA_HOME")
- if java_home:
- java_path = os.path.join(java_home, "bin", "java.exe" if platform.system() == "Windows" else "java")
- if os.path.exists(java_path):
- version = get_java_version(java_path)
- if version and (not required_version or check_java_version(version, required_version)):
- possible_paths.append((java_path, version))
- log_to_console(None, f"Znaleziono Javę w JAVA_HOME: {java_path} (wersja: {version})", "INFO")
- for base in [os.environ.get('ProgramFiles'), os.environ.get('ProgramFiles(x86)'), "C:\\Program Files\\Java", "C:\\Program Files (x86)\\Java"]:
- if base:
- java_dir = os.path.join(base, "Java")
- if os.path.isdir(java_dir):
- for item in os.listdir(java_dir):
- java_path = os.path.join(java_dir, item, "bin", "java.exe")
- if os.path.exists(java_path):
- version = get_java_version(java_path)
- if version and (not required_version or check_java_version(version, required_version)):
- possible_paths.append((java_path, version))
- log_to_console(None, f"Znaleziono Javę w {java_path} (wersja: {version})", "INFO")
- try:
- out = subprocess.check_output(["where", "java"], stderr=subprocess.DEVNULL).decode()
- for line in out.splitlines():
- line = line.strip()
- if os.path.exists(line) and line not in [p[0] for p in possible_paths]:
- version = get_java_version(line)
- if version and (not required_version or check_java_version(version, required_version)):
- possible_paths.append((line, version))
- log_to_console(None, f"Znaleziono Javę w {line} (wersja: {version})", "INFO")
- except:
- pass
- if not possible_paths:
- log_to_console(None, f"Nie znaleziono Javy {required_version}! Spróbuj pobrać automatycznie.", "ERROR")
- return possible_paths
- def get_java_version(java_path):
- try:
- result = subprocess.run([java_path, "-version"], stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
- version_line = result.stderr.split('\n')[0]
- version_match = re.search(r'version "([^"]+)"', version_line)
- if version_match:
- version = version_match.group(1)
- is_64bit = "64-Bit" in result.stderr
- log_to_console(None, f"Java {java_path}: {version}, 64-bit: {is_64bit}", "INFO")
- return version if is_64bit else None
- except Exception as e:
- log_to_console(None, f"Błąd sprawdzania wersji Javy {java_path}: {e}", "ERROR")
- return None
- def check_java_version(installed_version, required_version):
- try:
- installed = installed_version.split("_")[0]
- if required_version == "1.8":
- return installed.startswith("1.8.")
- if required_version == "16":
- return installed.startswith("16.")
- if required_version == "17":
- return installed.startswith("17.")
- if required_version == "21":
- return installed.startswith("21.")
- return pkg_version.parse(installed) >= pkg_version.parse(required_version)
- except:
- return False
- def is_new_launcher(version):
- try:
- ver_match = re.match(r'1\.(\d+)', version)
- if ver_match:
- ver_float = float(ver_match.group(1))
- return ver_float >= 6
- return True
- except:
- return True
- def get_required_java(version, version_info):
- if version_info and "javaVersion" in version_info:
- major_version = version_info["javaVersion"].get("majorVersion", 8)
- return str(major_version)
- try:
- if re.match(r'(\d+w\d+[a-z])', version): # Snapshoty
- return "1.8" # Większość starych snapshotów używa Javy 8
- ver = pkg_version.parse(version)
- if ver >= pkg_version.parse("1.21"):
- return "21"
- if ver >= pkg_version.parse("1.17"):
- return "17" # 1.18 też używa Javy 17
- return "1.8"
- except pkg_version.InvalidVersion:
- return "1.8" # Domyślnie dla niestandardowych wersji
- def download_file(url, path, progress_callback, expected_sha1=None, console=None):
- try:
- resp = requests.get(url, stream=True, timeout=10)
- resp.raise_for_status()
- total_size = int(resp.headers.get('content-length', 0))
- downloaded_size = 0
- os.makedirs(os.path.dirname(path), exist_ok=True)
- with open(path, "wb") as f:
- for chunk in resp.iter_content(chunk_size=8192):
- if chunk:
- f.write(chunk)
- downloaded_size += len(chunk)
- if total_size > 0 and progress_callback:
- progress_callback(downloaded_size, total_size)
- if expected_sha1 and not verify_sha1(path, expected_sha1):
- log_to_console(console, f"Błąd SHA1 dla {path}", "ERROR")
- return False
- return True
- except Exception as e:
- log_to_console(console, f"Błąd pobierania {path}: {e}", "ERROR")
- return False
- def download_assets(version, version_info, version_dir, shared_assets, console):
- try:
- asset_index = version_info.get("assetIndex", {})
- asset_url = asset_index.get("url")
- asset_id = asset_index.get("id")
- if not asset_url:
- log_to_console(console, "Brak assetIndex dla tej wersji", "WARNING")
- return True
- resp = requests.get(asset_url, timeout=10)
- resp.raise_for_status()
- assets_data = resp.json()
- assets_dir = ASSETS_DIR if shared_assets else os.path.join(version_dir, "assets")
- objects_dir = os.path.join(assets_dir, "objects")
- indexes_dir = os.path.join(assets_dir, "indexes")
- os.makedirs(objects_dir, exist_ok=True)
- os.makedirs(indexes_dir, exist_ok=True)
- index_file = os.path.join(indexes_dir, f"{asset_id}.json")
- log_to_console(console, f"Zapisywanie indeksu assetów: {index_file}", "INFO")
- with open(index_file, "w", encoding="utf-8") as f:
- json.dump(assets_data, f)
- total_assets = len(assets_data["objects"])
- total_size = sum(asset["size"] for asset in assets_data["objects"].values())
- downloaded_size = 0
- for i, (asset_name, asset_info) in enumerate(assets_data["objects"].items()):
- asset_hash = asset_info["hash"]
- asset_size = asset_info["size"]
- asset_subpath = f"{asset_hash[:2]}/{asset_hash}"
- asset_path = os.path.join(objects_dir, asset_subpath)
- asset_url = f"https://resources.download.minecraft.net/{asset_subpath}"
- if not os.path.exists(asset_path):
- log_to_console(console, f"Pobieranie assetu: {asset_name}", "INFO")
- if not download_file(
- asset_url, asset_path,
- lambda d, t: update_progress(global_progress_bar, global_status_label, (d/t)*100, t-d, "assets", i+1, total_assets),
- expected_sha1=asset_hash, console=console
- ):
- return False
- downloaded_size += asset_size
- update_progress(global_progress_bar, global_status_label, (downloaded_size/total_size)*100,
- total_size-downloaded_size, "assets", i+1, total_assets)
- return True
- except Exception as e:
- log_to_console(console, f"Błąd pobierania assetów: {e}", "ERROR")
- return False
- def download_natives(version, version_info, version_dir, shared_natives, console):
- try:
- libraries = version_info.get("libraries", [])
- natives_dir = NATIVES_DIR if shared_natives else os.path.join(version_dir, "natives")
- os.makedirs(natives_dir, exist_ok=True)
- system = platform.system().lower()
- natives_classifier = "natives-windows" if system == "windows" else "natives-osx" if system == "darwin" else "natives-linux"
- total_size = 0
- natives_to_download = []
- for lib in libraries:
- if "downloads" in lib and "classifiers" in lib["downloads"]:
- classifiers = lib["downloads"]["classifiers"]
- if natives_classifier in classifiers:
- artifact = classifiers[natives_classifier]
- natives_to_download.append(artifact)
- total_size += artifact.get("size", 0)
- log_to_console(console, f"Pobieranie {len(natives_to_download)} natywnych bibliotek", "INFO")
- downloaded_size = 0
- for i, artifact in enumerate(natives_to_download):
- native_url = artifact["url"]
- native_sha1 = artifact["sha1"]
- native_size = artifact.get("size", 0)
- native_path = os.path.join(version_dir, f"temp_native_{i}.jar")
- log_to_console(console, f"Pobieranie natywnej biblioteki: {native_url}", "INFO")
- if not download_file(
- native_url, native_path,
- lambda d, t: update_progress(global_progress_bar, global_status_label, (d/t)*100, t-d, "natives", i+1, len(natives_to_download)),
- expected_sha1=native_sha1, console=console
- ):
- return False
- with zipfile.ZipFile(native_path, 'r') as zip_ref:
- zip_ref.extractall(natives_dir)
- os.remove(native_path)
- downloaded_size += native_size
- update_progress(global_progress_bar, global_status_label, (downloaded_size/total_size)*100,
- total_size-downloaded_size, "natives", i+1, len(natives_to_download))
- return True
- except Exception as e:
- log_to_console(console, f"Błąd pobierania natywnych bibliotek: {e}", "ERROR")
- return False
- def verify_instance(version, console):
- instance = instances.get(version)
- if not instance:
- log_to_console(console, f"Instancja {version} nie istnieje!", "ERROR")
- messagebox.showerror("Błąd", f"Instancja {version} nie istnieje!")
- return False
- version_dir = instance["path"]
- settings = instance["settings"]
- info = get_version_info(version)
- if not info:
- log_to_console(console, f"Nie udało się pobrać info o wersji {version}", "ERROR")
- return False
- log_to_console(console, f"Weryfikacja instancji {version}...", "INFO")
- all_valid = True
- # Sprawdź client.jar
- client_path = os.path.join(version_dir, f"{version}.jar")
- client_sha1 = info["downloads"]["client"]["sha1"]
- if not os.path.exists(client_path):
- log_to_console(console, f"Brak client.jar dla {version}", "ERROR")
- all_valid = False
- elif not verify_sha1(client_path, client_sha1):
- log_to_console(console, f"Błąd SHA1 dla client.jar ({version})", "ERROR")
- all_valid = False
- else:
- log_to_console(console, f"client.jar OK", "INFO")
- # Sprawdź biblioteki
- libraries_dir = LIBRARIES_DIR if settings.get("shared_libraries", True) else os.path.join(version_dir, "libraries")
- for lib in info.get("libraries", []):
- if "downloads" in lib and "artifact" in lib["downloads"]:
- artifact = lib["downloads"]["artifact"]
- lib_path = artifact["path"].replace("/", os.sep)
- full_lib_path = os.path.join(libraries_dir, lib_path)
- lib_sha1 = artifact["sha1"]
- if not os.path.exists(full_lib_path):
- log_to_console(console, f"Brak biblioteki {lib_path}", "ERROR")
- all_valid = False
- elif not verify_sha1(full_lib_path, lib_sha1):
- log_to_console(console, f"Błąd SHA1 dla biblioteki {lib_path}", "ERROR")
- all_valid = False
- else:
- log_to_console(console, f"Biblioteka {lib_path} OK", "INFO")
- # Sprawdź natywne biblioteki
- natives_dir = NATIVES_DIR if settings.get("shared_natives", True) else os.path.join(version_dir, "natives")
- system = platform.system().lower()
- natives_classifier = "natives-windows" if system == "windows" else "natives-osx" if system == "darwin" else "natives-linux"
- for lib in info.get("libraries", []):
- if "downloads" in lib and "classifiers" in lib["downloads"]:
- classifiers = lib["downloads"]["classifiers"]
- if natives_classifier in classifiers:
- artifact = classifiers[natives_classifier]
- native_path = os.path.join(version_dir, f"temp_native_check.jar")
- if not download_file(artifact["url"], native_path, None, artifact["sha1"], console):
- log_to_console(console, f"Błąd weryfikacji natywnej biblioteki {artifact['url']}", "ERROR")
- all_valid = False
- else:
- log_to_console(console, f"Natywna biblioteka {artifact['url']} OK", "INFO")
- if os.path.exists(native_path):
- os.remove(native_path)
- # Sprawdź assets
- assets_dir = ASSETS_DIR if settings.get("shared_assets", True) else os.path.join(version_dir, "assets")
- asset_index = info.get("assetIndex", {})
- if asset_index.get("url"):
- resp = requests.get(asset_index["url"], timeout=10)
- if resp.status_code == 200:
- assets_data = resp.json()
- for asset_name, asset_info in assets_data["objects"].items():
- asset_hash = asset_info["hash"]
- asset_subpath = f"{asset_hash[:2]}/{asset_hash}"
- asset_path = os.path.join(assets_dir, "objects", asset_subpath)
- if not os.path.exists(asset_path):
- log_to_console(console, f"Brak assetu {asset_name}", "ERROR")
- all_valid = False
- elif not verify_sha1(asset_path, asset_hash):
- log_to_console(console, f"Błąd SHA1 dla assetu {asset_name}", "ERROR")
- all_valid = False
- else:
- log_to_console(console, f"Asset {asset_name} OK", "INFO")
- else:
- log_to_console(console, f"Nie udało się pobrać indeksu assetów", "ERROR")
- all_valid = False
- # Sprawdź i zregeneruj start.bat
- bat_path = os.path.join(version_dir, "start.bat")
- if not os.path.exists(bat_path):
- log_to_console(console, f"Brak start.bat dla {version}, regeneruję...", "WARNING")
- all_valid = False
- else:
- log_to_console(console, f"start.bat OK, regeneruję dla pewności...", "INFO")
- # Regeneracja start.bat
- classpath = f"{version}.jar"
- for lib in info.get("libraries", []):
- if "downloads" in lib and "artifact" in lib["downloads"]:
- lib_path = lib["downloads"]["artifact"]["path"].replace("/", os.sep)
- classpath += f";{os.path.join(libraries_dir, lib_path)}"
- assets_path = ASSETS_DIR if settings.get("shared_assets", True) else os.path.join(version_dir, "assets")
- natives_path = NATIVES_DIR if settings.get("shared_natives", True) else os.path.join(version_dir, "natives")
- java_path = instance.get("java_path", "")
- asset_index = info.get("assetIndex", {}).get("id", version)
- with open(bat_path, "w", encoding="utf-8") as f:
- if is_new_launcher(version):
- f.write(f'@echo off\n')
- f.write(f'title Minecraft {version}\n')
- f.write(f'"{java_path}" -Xmx{settings["memory"]}G -Djava.library.path="{natives_path}" -Dorg.lwjgl.util.Debug=true -cp "{classpath}" net.minecraft.client.main.Main ')
- f.write(f'--username {settings["username"]} --version {version} --gameDir . ')
- f.write(f'--assetsDir "{assets_path}" --assetIndex {asset_index} ')
- f.write(f'--accessToken null --uuid 0 --userType legacy\n')
- f.write(f'pause\n')
- else:
- f.write(f'@echo off\n')
- f.write(f'title Minecraft {version}\n')
- f.write(f'"{java_path}" -Xmx{settings["memory"]}G -cp "{version}.jar" net.minecraft.LauncherFrame {settings["username"]} player_session_id\n')
- f.write(f'pause\n')
- log_to_console(console, f"start.bat zregenerowany dla {version}", "SUCCESS")
- if all_valid:
- log_to_console(console, f"Instancja {version} zweryfikowana poprawnie!", "SUCCESS")
- messagebox.showinfo("Sukces", f"Instancja {version} jest kompletna!")
- else:
- log_to_console(console, f"Weryfikacja instancji {version} nieudana, ale start.bat zregenerowany!", "WARNING")
- messagebox.showwarning("Uwaga", f"Instancja {version} miała problemy, ale start.bat został zregenerowany!")
- return all_valid
- def update_progress(progress_bar, status_label, progress, remaining, stage, current, total):
- if progress_bar and status_label:
- progress_bar["value"] = progress
- remaining_str = humanize.naturalsize(remaining) if remaining else "0 B"
- status_label.config(text=f"[{stage}] Postęp: {progress:.1f}% | Pozostało: {remaining_str} | {current}/{total}")
- root.update()
- def download_version(version, instance_settings, console):
- global download_active
- download_active = True
- info = get_version_info(version)
- if not info:
- download_active = False
- return
- java_major_version = get_required_java(version, info)
- log_to_console(console, f"Wymagana Java: {java_major_version}", "INFO")
- java_paths = find_java(java_major_version)
- if not java_paths:
- if messagebox.askyesno("Brak Javy", f"Nie znaleziono Javy {java_major_version}. Pobrać automatycznie?"):
- java_path, java_version = download_java(java_major_version, console)
- if java_path:
- java_paths = [(java_path, java_version)]
- else:
- log_to_console(console, f"Nie udało się pobrać Javy {java_major_version}!", "ERROR")
- messagebox.showerror("Błąd", f"Nie udało się pobrać Javy {java_major_version}!")
- download_active = False
- return
- else:
- log_to_console(console, f"Nie znaleziono Javy {java_major_version}! Wskaż ręcznie.", "ERROR")
- messagebox.showerror("Błąd", f"Nie znaleziono Javy {java_major_version}! Pobierz z adoptium.net.")
- download_active = False
- return
- java_path, java_version = java_paths[0]
- if instance_settings.get("java_path"):
- java_path = instance_settings["java_path"]
- java_version = get_java_version(java_path) or java_version
- log_to_console(console, f"Używam Javy: {java_path} (wersja {java_version})", "INFO")
- version_dir = os.path.join(BASE_DIR, "instances", version)
- os.makedirs(version_dir, exist_ok=True)
- libraries_dir = LIBRARIES_DIR if instance_settings.get("shared_libraries", True) else os.path.join(version_dir, "libraries")
- os.makedirs(libraries_dir, exist_ok=True)
- # Etap 1: Client.jar
- update_progress(global_progress_bar, global_status_label, 0, 0, "client.jar", 1, 1)
- global_status_label.config(text="[1/5] Pobieranie client.jar...")
- client_url = info["downloads"]["client"]["url"]
- client_sha1 = info["downloads"]["client"]["sha1"]
- client_path = os.path.join(version_dir, f"{version}.jar")
- log_to_console(console, f"Pobieranie client.jar dla {version}", "INFO")
- if not download_file(
- client_url, client_path,
- lambda d, t: update_progress(global_progress_bar, global_status_label, (d/t)*100, t-d, "client.jar", 1, 1),
- expected_sha1=client_sha1, console=console
- ):
- download_active = False
- return
- # Etap 2: Biblioteki
- update_progress(global_progress_bar, global_status_label, 0, 0, "biblioteki", 0, 0)
- global_status_label.config(text="[2/5] Pobieranie bibliotek...")
- libs = info.get("libraries", [])
- total_libs_size = 0
- libs_to_download = []
- for lib in libs:
- if "downloads" in lib and "artifact" in lib["downloads"]:
- artifact = lib["downloads"]["artifact"]
- lib_path = artifact["path"].replace("/", os.sep)
- full_lib_path = os.path.join(libraries_dir, lib_path)
- if not os.path.exists(full_lib_path):
- libs_to_download.append((lib, artifact))
- total_libs_size += artifact.get("size", 0)
- log_to_console(console, f"Pobieranie {len(libs_to_download)} bibliotek", "INFO")
- downloaded_libs_size = 0
- for i, (lib, artifact) in enumerate(libs_to_download):
- lib_path = artifact["path"].replace("/", os.sep)
- full_lib_path = os.path.join(libraries_dir, lib_path)
- lib_url = artifact["url"]
- lib_sha1 = artifact["sha1"]
- lib_size = artifact.get("size", 0)
- log_to_console(console, f"Pobieranie biblioteki: {lib_path}", "INFO")
- if not download_file(
- lib_url, full_lib_path,
- lambda d, t: update_progress(global_progress_bar, global_status_label, (d/t)*100, t-d, "biblioteki", i+1, len(libs_to_download)),
- expected_sha1=lib_sha1, console=console
- ):
- download_active = False
- downloaded_libs_size += lib_size
- update_progress(global_progress_bar, global_status_label, (downloaded_libs_size/total_libs_size)*100,
- total_libs_size-downloaded_libs_size, "biblioteki", i+1, len(libs_to_download))
- # Etap 3: Natives
- update_progress(global_progress_bar, global_status_label, 0, 0, "natives", 0, 0)
- global_status_label.config(text="[3/5] Pobieranie natywnych bibliotek...")
- if not download_natives(version, info, version_dir, instance_settings.get("shared_natives", True), console):
- download_active = False
- return
- # Etap 4: Assets
- update_progress(global_progress_bar, global_status_label, 0, 0, "assets", 0, 0)
- global_status_label.config(text="[4/5] Pobieranie assetów...")
- if not download_assets(version, info, version_dir, instance_settings.get("shared_assets", True), console):
- download_active = False
- return
- # Etap 5: Generowanie start.bat
- update_progress(global_progress_bar, global_status_label, 0, 0, "start.bat", 1, 1)
- global_status_label.config(text="[5/5] Generowanie start.bat...")
- bat_path = os.path.join(version_dir, "start.bat")
- classpath = f"{version}.jar"
- for lib in libs:
- if "downloads" in lib and "artifact" in lib["downloads"]:
- lib_path = lib["downloads"]["artifact"]["path"].replace("/", os.sep)
- classpath += f";{os.path.join(libraries_dir, lib_path)}"
- assets_path = ASSETS_DIR if instance_settings.get("shared_assets", True) else os.path.join(version_dir, "assets")
- natives_path = NATIVES_DIR if instance_settings.get("shared_natives", True) else os.path.join(version_dir, "natives")
- username = instance_settings.get("username", "Player").strip() or "Player"
- memory = instance_settings.get("memory", "2")
- asset_index = info.get("assetIndex", {}).get("id", version)
- with open(bat_path, "w", encoding="utf-8") as f:
- if is_new_launcher(version):
- f.write(f'@echo off\n')
- f.write(f'title Minecraft {version}\n')
- f.write(f'"{java_path}" -Xmx{memory}G -Djava.library.path="{natives_path}" -Dorg.lwjgl.util.Debug=true -cp "{classpath}" net.minecraft.client.main.Main ')
- f.write(f'--username {username} --version {version} --gameDir . ')
- f.write(f'--assetsDir "{assets_path}" --assetIndex {asset_index} ')
- f.write(f'--accessToken null --uuid 0 --userType legacy\n')
- f.write(f'pause\n')
- else:
- f.write(f'@echo off\n')
- f.write(f'title Minecraft {version}\n')
- f.write(f'"{java_path}" -Xmx{memory}G -cp "{version}.jar" net.minecraft.LauncherFrame {username} player_session_id\n')
- f.write(f'pause\n')
- instances[version] = {
- "path": version_dir,
- "java_path": java_path,
- "java_version": java_version,
- "required_java": java_major_version,
- "settings": instance_settings,
- "ready": True,
- "timestamp": datetime.now().isoformat()
- }
- save_config()
- update_progress(global_progress_bar, global_status_label, 100, 0, "gotowe", 1, 1)
- global_status_label.config(text="Gotowe!")
- log_to_console(console, f"Instancja {version} pobrana!", "SUCCESS")
- messagebox.showinfo("Sukces", f"Instancja {version} gotowa!")
- refresh_instances()
- download_active = False
- def run_game(version):
- instance = instances.get(version)
- if not instance or not instance.get("ready"):
- messagebox.showerror("Błąd", f"Instancja {version} nie jest gotowa!")
- return
- bat_path = os.path.join(instance["path"], "start.bat")
- if os.path.exists(bat_path):
- try:
- subprocess.Popen(bat_path, cwd=instance["path"], shell=True)
- log_to_console(console, f"Uruchomiono Minecraft {version}", "SUCCESS")
- except Exception as e:
- log_to_console(console, f"Nie udało się uruchomić gry: {e}", "ERROR")
- messagebox.showerror("Błąd", f"Nie udało się uruchomić gry: {e}")
- else:
- messagebox.showerror("Błąd", f"Brak start.bat dla {version}!")
- def delete_instance(version):
- if messagebox.askyesno("Potwierdź", f"Na pewno usunąć instancję {version}?"):
- instance = instances.get(version)
- if instance:
- import shutil
- try:
- shutil.rmtree(instance["path"])
- del instances[version]
- save_config()
- log_to_console(console, f"Instancja {version} usunięta", "SUCCESS")
- refresh_instances()
- except Exception as e:
- log_to_console(console, f"Błąd usuwania instancji {version}: {e}", "ERROR")
- def copy_console(console):
- console.config(state="normal")
- content = console.get("1.0", tk.END).strip()
- pyperclip.copy(content)
- console.config(state="disabled")
- messagebox.showinfo("Sukces", "Konsola skopiowana!")
- def clear_console(console):
- console.config(state="normal")
- console.delete("1.0", tk.END)
- console.config(state="disabled")
- if __name__ == "__main__":
- try:
- print(f"{Fore.LIGHTCYAN_EX}{Fore.LIGHTCYAN_EX}[Inicjalizacja Tkinter...")
- root = tk.Tk()
- print(f"{Fore.LIGHTCYAN_EX}{Fore.LIGHTCYAN_EX}[Tkinter zainicjalizowany.")
- root.title("Minecraft Launcher by Paffcio")
- root.geometry("1000x750")
- root.configure(bg=BG_COLOR)
- root.minsize(900, 650)
- print(f"{Fore.LIGHTCYAN_EX}{Fore.LIGHTCYAN_EX}Ładowanie konfiguracji...")
- # Inicjalizacja zmiennych Tkinter przed ładowaniem konfiguracji
- username_var = tk.StringVar(value="Player")
- memory_var = tk.StringVar(value="2")
- shared_assets_var = tk.BooleanVar(value=True)
- shared_libraries_var = tk.BooleanVar(value=True)
- shared_natives_var = tk.BooleanVar(value=True)
- snapshots_var = tk.BooleanVar(value=True)
- releases_var = tk.BooleanVar(value=True)
- alpha_var = tk.BooleanVar(value=False)
- beta_var = tk.BooleanVar(value=False)
- current_tab = tk.StringVar(value="Instancje")
- # Teraz ładujemy konfigurację, która zaktualizuje zmienne
- instances, java_versions_cache = load_config()
- print(f"{Fore.LIGHTCYAN_EX}{Fore.LIGHTCYAN_EX}Konfiguracja wczytana.")
- print(f"{Fore.LIGHTCYAN_EX}{Fore.LIGHTCYAN_EX}Tworzenie zmiennych Tkinter...")
- print(f"{Fore.LIGHTCYAN_EX}{Fore.LIGHTCYAN_EX}Zmienne utworzone.")
- print(f"{Fore.LIGHTCYAN_EX}{Fore.LIGHTCYAN_EX}Inicjalizacja UI...")
- style = ttk.Style()
- style.theme_use('clam')
- style.configure("TFrame", background=BG_COLOR)
- style.configure("TLabel", background=BG_COLOR, foreground=FG_COLOR, font=("Segoe UI", 10))
- style.configure("TButton", background=BUTTON_BG, foreground=FG_COLOR, font=("Segoe UI", 10), borderwidth=0)
- style.map("TButton",
- background=[('active', BUTTON_HOVER), ('pressed', BUTTON_HOVER)],
- foreground=[('active', FG_COLOR), ('pressed', FG_COLOR)])
- style.configure("TEntry", fieldbackground="#333333", foreground=FG_COLOR, insertcolor=FG_COLOR, borderwidth=1)
- style.configure("TCombobox", fieldbackground="#333333", foreground=FG_COLOR, selectbackground=ACCENT_COLOR)
- style.configure("Horizontal.TProgressbar", troughcolor="#333333", background=ACCENT_COLOR, thickness=10)
- style.configure("Treeview", background="#333333", fieldbackground="#333333", foreground=FG_COLOR, rowheight=25)
- style.map("Treeview", background=[('selected', ACCENT_COLOR)])
- style.configure("Treeview.Heading", background=SIDEBAR_BG, foreground=FG_COLOR, font=("Segoe UI", 10, "bold"))
- progress_frame = ttk.Frame(root)
- progress_frame.pack(side="bottom", fill="x", padx=10, pady=5)
- global_progress_bar = ttk.Progressbar(progress_frame, length=400, mode="determinate", style="Horizontal.TProgressbar")
- global_progress_bar.pack(fill="x")
- global_status_label = ttk.Label(progress_frame, text="Gotowe do działania!", foreground=FG_COLOR, background=BG_COLOR, font=("Segoe UI", 9))
- global_status_label.pack()
- sidebar = tk.Frame(root, bg=SIDEBAR_BG, width=220)
- sidebar.pack(side="left", fill="y", padx=0, pady=0)
- logo_frame = tk.Frame(sidebar, bg=SIDEBAR_BG)
- logo_frame.pack(fill="x", pady=(10, 20))
- try:
- print(f"{Fore.LIGHTCYAN_EX}{Fore.LIGHTCYAN_EX}Ładowanie logo...")
- logo_img = Image.open(os.path.join(ICONS_DIR, "logo.png")) if os.path.exists(ICONS_DIR) else None
- if logo_img:
- logo_img = logo_img.resize((180, 60), Image.LANCZOS)
- logo_photo = ImageTk.PhotoImage(logo_img)
- logo_label = tk.Label(logo_frame, image=logo_photo, bg=SIDEBAR_BG)
- logo_label.image = logo_photo
- logo_label.pack(pady=5)
- print(f"{Fore.LIGHTCYAN_EX}{Fore.LIGHTCYAN_EX}Logo załadowane.")
- except Exception as e:
- print(f"{Fore.LIGHTCYAN_EX}Błąd ładowania logo: {e}")
- tabs = [
- ("Instancje", "📋"),
- ("Pobieranie", "⬇"),
- ("Ustawienia", "⚙"),
- ("Konsola", "📜")
- ]
- tab_buttons = {}
- for tab_name, icon in tabs:
- print(f"{Fore.LIGHTCYAN_EX}Tworzenie przycisku {tab_name}...")
- btn = tk.Button(
- sidebar, text=f" {icon} {tab_name}", bg=SIDEBAR_BG, fg=FG_COLOR,
- activebackground=ACTIVE_TAB_COLOR, activeforeground=FG_COLOR,
- font=("Segoe UI", 11), relief="flat", anchor="w", padx=15, pady=10,
- command=lambda t=tab_name: switch_tab(t)
- )
- btn.pack(fill="x", pady=0)
- tab_buttons[tab_name] = btn
- btn.bind("<Enter>", lambda e, b=btn: b.config(bg=HOVER_TAB_COLOR) if current_tab.get() != tab_name else None)
- btn.bind("<Leave>", lambda e, b=btn: b.config(bg=SIDEBAR_BG) if current_tab.get() != tab_name else None)
- print(f"{Fore.LIGHTCYAN_EX}Przycisk {tab_name} utworzony.")
- content_frame = ttk.Frame(root)
- content_frame.pack(side="left", fill="both", expand=True, padx=10, pady=10)
- def switch_tab(tab_name):
- global download_active
- if download_active and tab_name != "Pobieranie":
- if not messagebox.askyesno("Ostrzeżenie", "Pobieranie w toku! Zmiana zakładki przerwie proces. Kontynuować?"):
- return
- download_active = False
- current_tab.set(tab_name)
- for name, btn in tab_buttons.items():
- if name == tab_name:
- btn.config(bg=ACTIVE_TAB_COLOR, relief="sunken")
- else:
- btn.config(bg=SIDEBAR_BG, relief="flat")
- for widget in content_frame.winfo_children():
- widget.destroy()
- if tab_name == "Instancje":
- show_instances()
- elif tab_name == "Pobieranie":
- show_download()
- elif tab_name == "Ustawienia":
- show_settings()
- elif tab_name == "Konsola":
- show_console()
- def show_instances():
- frame = ttk.Frame(content_frame)
- frame.pack(fill="both", expand=True)
- header_frame = ttk.Frame(frame)
- header_frame.pack(fill="x", pady=(0, 10))
- ttk.Label(header_frame, text="Twoje instancje Minecraft", font=("Segoe UI", 14, "bold")).pack(side="left")
- btn_frame = ttk.Frame(header_frame)
- btn_frame.pack(side="right")
- refresh_btn = ttk.Button(btn_frame, text="Odśwież", command=refresh_instances, width=10)
- refresh_btn.pack(side="left", padx=5)
- new_btn = ttk.Button(btn_frame, text="Nowa instancja", command=create_instance, width=15)
- new_btn.pack(side="left", padx=5)
- tree_frame = ttk.Frame(frame)
- tree_frame.pack(fill="both", expand=True)
- columns = ("version", "java", "status", "date")
- tree = ttk.Treeview(
- tree_frame, columns=columns, show="headings", selectmode="browse",
- style="Treeview"
- )
- tree.heading("version", text="Wersja", anchor="w")
- tree.heading("java", text="Java", anchor="w")
- tree.heading("status", text="Status", anchor="w")
- tree.heading("date", text="Data utworzenia", anchor="w")
- tree.column("version", width=150, anchor="w")
- tree.column("java", width=100, anchor="w")
- tree.column("status", width=80, anchor="w")
- tree.column("date", width=120, anchor="w")
- scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=tree.yview)
- scrollbar.pack(side="right", fill="y")
- tree.configure(yscrollcommand=scrollbar.set)
- tree.pack(fill="both", expand=True)
- for version, data in instances.items():
- tree.insert("", "end", values=(
- version,
- data.get("java_version", "?"),
- "Gotowe" if data.get("ready", False) else "Błąd",
- datetime.fromisoformat(data["timestamp"]).strftime("%Y-%m-%d %H:%M")
- ))
- action_frame = ttk.Frame(frame)
- action_frame.pack(fill="x", pady=(10, 0))
- run_btn = ttk.Button(action_frame, text="Uruchom", command=lambda: run_game(tree.item(tree.selection())["values"][0] if tree.selection() else ""), width=15)
- run_btn.pack(side="left", padx=5)
- edit_btn = ttk.Button(action_frame, text="Edytuj", command=lambda: edit_instance(tree.item(tree.selection())["values"][0] if tree.selection() else ""), width=15)
- edit_btn.pack(side="left", padx=5)
- verify_btn = ttk.Button(action_frame, text="Sprawdź", command=lambda: verify_instance(tree.item(tree.selection())["values"][0] if tree.selection() else "", console), width=15)
- verify_btn.pack(side="left", padx=5)
- delete_btn = ttk.Button(action_frame, text="Usuń", command=lambda: delete_instance(tree.item(tree.selection())["values"][0] if tree.selection() else ""), width=15)
- delete_btn.pack(side="left", padx=5)
- ttk.Label(frame, text="Wybierz instancję i kliknij odpowiedni przycisk", font=("Segoe UI", 9)).pack(pady=(10, 0))
- def refresh_instances():
- for widget in content_frame.winfo_children():
- widget.destroy()
- show_instances()
- def create_instance():
- window = tk.Toplevel(root)
- window.title("Nowa instancja Minecraft")
- window.geometry("500x650")
- window.configure(bg=BG_COLOR)
- window.resizable(False, False)
- style.configure("NewInstance.TFrame", background=BG_COLOR)
- style.configure("NewInstance.TLabel", background=BG_COLOR, foreground=FG_COLOR, font=("Segoe UI", 10))
- style.configure("NewInstance.TButton", background=BUTTON_BG, foreground=FG_COLOR, font=("Segoe UI", 10))
- frame = ttk.Frame(window, style="NewInstance.TFrame", padding="15")
- frame.pack(fill="both", expand=True)
- ttk.Label(frame, text="Tworzenie nowej instancji", font=("Segoe UI", 14, "bold")).pack(pady=(0, 15))
- form_frame = ttk.Frame(frame)
- form_frame.pack(fill="both", expand=True)
- ttk.Label(form_frame, text="Filtry wersji:").grid(row=0, column=0, sticky="w", pady=(0, 5))
- filters_frame = ttk.Frame(form_frame)
- filters_frame.grid(row=0, column=1, sticky="w", pady=(0, 5))
- tk.Checkbutton(filters_frame, text="Snapshoty", variable=snapshots_var, bg=BG_COLOR, fg=FG_COLOR,
- selectcolor=BG_COLOR, activebackground=BG_COLOR, font=("Segoe UI", 9),
- command=lambda: [save_config(), refresh_version_combo(version_combo, version_var)]).pack(anchor="w", pady=2)
- tk.Checkbutton(filters_frame, text="Release", variable=releases_var, bg=BG_COLOR, fg=FG_COLOR,
- selectcolor=BG_COLOR, activebackground=BG_COLOR, font=("Segoe UI", 9),
- command=lambda: [save_config(), refresh_version_combo(version_combo, version_var)]).pack(anchor="w", pady=2)
- tk.Checkbutton(filters_frame, text="Alpha", variable=alpha_var, bg=BG_COLOR, fg=FG_COLOR,
- selectcolor=BG_COLOR, activebackground=BG_COLOR, font=("Segoe UI", 9),
- command=lambda: [save_config(), refresh_version_combo(version_combo, version_var)]).pack(anchor="w", pady=2)
- tk.Checkbutton(filters_frame, text="Beta", variable=beta_var, bg=BG_COLOR, fg=FG_COLOR,
- selectcolor=BG_COLOR, activebackground=BG_COLOR, font=("Segoe UI", 9),
- command=lambda: [save_config(), refresh_version_combo(version_combo, version_var)]).pack(anchor="w", pady=2)
- ttk.Label(form_frame, text="Wersja Minecrafta:").grid(row=1, column=0, sticky="w", pady=(10, 5))
- version_var = tk.StringVar()
- versions = get_versions()
- version_combo = ttk.Combobox(form_frame, textvariable=version_var, state="readonly", values=versions)
- version_combo.grid(row=1, column=1, sticky="ew", pady=(10, 5), padx=(5, 0))
- if versions:
- version_combo.current(0)
- else:
- messagebox.showwarning("Uwaga", "Włącz przynajmniej jeden filtr wersji (Snapshoty, Release, Alpha, Beta)!")
- ttk.Label(form_frame, text="Nazwa użytkownika:").grid(row=2, column=0, sticky="w", pady=(10, 5))
- username_entry = ttk.Entry(form_frame)
- username_entry.insert(0, username_var.get())
- username_entry.grid(row=2, column=1, sticky="ew", pady=(10, 5), padx=(5, 0))
- ttk.Label(form_frame, text="Pamięć RAM (GB):").grid(row=3, column=0, sticky="w", pady=(10, 5))
- memory_spin = tk.Spinbox(form_frame, from_=1, to=16, width=5, bg="#333333", fg=FG_COLOR, highlightthickness=0)
- memory_spin.delete(0, tk.END)
- memory_spin.insert(0, memory_var.get())
- memory_spin.grid(row=3, column=1, sticky="w", pady=(10, 5), padx=(5, 0))
- ttk.Label(form_frame, text="Ścieżka Java:").grid(row=4, column=0, sticky="w", pady=(10, 5))
- java_var = tk.StringVar()
- java_combo = ttk.Combobox(form_frame, textvariable=java_var, state="readonly")
- java_paths = find_java()
- java_combo['values'] = [f"{p} ({v})" for p, v in java_paths]
- java_combo.grid(row=4, column=1, sticky="ew", pady=(10, 5), padx=(5, 0))
- # Automatyczny wybór najlepszej Javy
- if versions and java_paths:
- version_info = get_version_info(version_var.get())
- required_java = get_required_java(version_var.get(), version_info)
- best_java_index = 0
- for i, (path, ver) in enumerate(java_paths):
- if check_java_version(ver, required_java):
- best_java_index = i
- break
- java_combo.current(best_java_index)
- # Aktualizacja Javy przy zmianie wersji Minecrafta
- def update_java_combo(event):
- version_info = get_version_info(version_var.get())
- required_java = get_required_java(version_var.get(), version_info)
- for i, (path, ver) in enumerate(java_paths):
- if check_java_version(ver, required_java):
- java_combo.current(i)
- break
- else:
- java_combo.current(0) if java_paths else java_combo.set("Brak Javy")
- version_combo.bind("<<ComboboxSelected>>", update_java_combo)
- options_frame = ttk.Frame(form_frame)
- options_frame.grid(row=5, column=0, columnspan=2, sticky="ew", pady=(10, 5))
- shared_assets = tk.BooleanVar(value=shared_assets_var.get())
- shared_libs = tk.BooleanVar(value=shared_libraries_var.get())
- shared_natives = tk.BooleanVar(value=shared_natives_var.get())
- tk.Checkbutton(options_frame, text="Współdziel assets", variable=shared_assets,
- bg=BG_COLOR, fg=FG_COLOR, selectcolor=BG_COLOR, activebackground=BG_COLOR,
- font=("Segoe UI", 9)).pack(anchor="w", pady=2)
- tk.Checkbutton(options_frame, text="Współdziel biblioteki", variable=shared_libs,
- bg=BG_COLOR, fg=FG_COLOR, selectcolor=BG_COLOR, activebackground=BG_COLOR,
- font=("Segoe UI", 9)).pack(anchor="w", pady=2)
- tk.Checkbutton(options_frame, text="Współdziel natywne biblioteki", variable=shared_natives,
- bg=BG_COLOR, fg=FG_COLOR, selectcolor=BG_COLOR, activebackground=BG_COLOR,
- font=("Segoe UI", 9)).pack(anchor="w", pady=2)
- btn_frame = ttk.Frame(frame)
- btn_frame.pack(fill="x", pady=(15, 0))
- ttk.Button(btn_frame, text="Anuluj", command=window.destroy, width=15).pack(side="right", padx=5)
- ttk.Button(btn_frame, text="Utwórz", command=lambda: [
- save_pending_instance({
- "username": username_entry.get(),
- "memory": memory_spin.get(),
- "java_path": java_paths[int(java_combo.current())][0] if java_combo.current() != -1 else "",
- "shared_assets": shared_assets.get(),
- "shared_libraries": shared_libs.get(),
- "shared_natives": shared_natives.get()
- }, version_var.get()),
- switch_tab("Pobieranie"),
- window.destroy()
- ] if version_var.get() else messagebox.showwarning("Uwaga", "Wybierz wersję!")).pack(side="right", padx=5)
- def save_pending_instance(settings, version):
- global pending_instance_settings, pending_version
- pending_instance_settings = settings
- pending_version = version
- def edit_instance(version):
- if not version or version not in instances:
- messagebox.showwarning("Uwaga", "Wybierz instancję!")
- return
- instance = instances[version]
- settings = instance.get("settings", {})
- window = tk.Toplevel(root)
- window.title(f"Edytuj instancję {version}")
- window.geometry("500x550")
- window.configure(bg=BG_COLOR)
- window.resizable(False, False)
- frame = ttk.Frame(window, padding="15")
- frame.pack(fill="both", expand=True)
- ttk.Label(frame, text=f"Edycja instancji {version}", font=("Segoe UI", 14, "bold")).pack(pady=(0, 15))
- form_frame = ttk.Frame(frame)
- form_frame.pack(fill="both", expand=True)
- ttk.Label(form_frame, text="Nazwa użytkownika:").grid(row=0, column=0, sticky="w", pady=(0, 5))
- username_entry = ttk.Entry(form_frame)
- username_entry.insert(0, settings.get("username", username_var.get()))
- username_entry.grid(row=0, column=1, sticky="ew", pady=(0, 5), padx=(5, 0))
- ttk.Label(form_frame, text="Pamięć RAM (GB):").grid(row=1, column=0, sticky="w", pady=(10, 5))
- memory_spin = tk.Spinbox(form_frame, from_=1, to=16, width=5, bg="#333333", fg=FG_COLOR, highlightthickness=0)
- memory_spin.delete(0, tk.END)
- memory_spin.insert(0, settings.get("memory", memory_var.get()))
- memory_spin.grid(row=1, column=1, sticky="w", pady=(10, 5), padx=(5, 0))
- ttk.Label(form_frame, text="Ścieżka Java:").grid(row=2, column=0, sticky="w", pady=(10, 5))
- java_var = tk.StringVar()
- java_combo = ttk.Combobox(form_frame, textvariable=java_var, state="readonly")
- java_paths = find_java()
- current_java = settings.get("java_path", instance.get("java_path", ""))
- java_values = [f"{p} ({v})" for p, v in java_paths]
- # Jeśli zapisana Java istnieje, dodaj ją do listy, jeśli nie ma jej w java_paths
- if current_java and not any(p == current_java for p, v in java_paths):
- java_values.append(f"{current_java} (zapisana)")
- java_paths.append((current_java, "zapisana"))
- java_combo['values'] = java_values
- java_combo.grid(row=2, column=1, sticky="ew", pady=(10, 5), padx=(5, 0))
- # Ustaw zapisana Javę, jeśli istnieje
- if current_java:
- for i, (path, ver) in enumerate(java_paths):
- if path == current_java:
- java_combo.current(i)
- break
- else:
- java_combo.current(len(java_paths) - 1) # Wybierz "zapisana", jeśli dodana
- elif java_paths:
- # Jeśli brak zapisanej Javy, wybierz najlepszą dla wersji
- version_info = get_version_info(version)
- required_java = get_required_java(version, version_info)
- for i, (path, ver) in enumerate(java_paths):
- if check_java_version(ver, required_java):
- java_combo.current(i)
- break
- else:
- java_combo.current(0)
- options_frame = ttk.Frame(form_frame)
- options_frame.grid(row=3, column=0, columnspan=2, sticky="ew", pady=(10, 5))
- shared_assets = tk.BooleanVar(value=settings.get("shared_assets", shared_assets_var.get()))
- shared_libs = tk.BooleanVar(value=settings.get("shared_libraries", shared_libraries_var.get()))
- shared_natives = tk.BooleanVar(value=settings.get("shared_natives", shared_natives_var.get()))
- tk.Checkbutton(options_frame, text="Współdziel assets", variable=shared_assets,
- bg=BG_COLOR, fg=FG_COLOR, selectcolor=BG_COLOR, activebackground=BG_COLOR,
- font=("Segoe UI", 9)).pack(anchor="w", pady=2)
- tk.Checkbutton(options_frame, text="Współdziel biblioteki", variable=shared_libs,
- bg=BG_COLOR, fg=FG_COLOR, selectcolor=BG_COLOR, activebackground=BG_COLOR,
- font=("Segoe UI", 9)).pack(anchor="w", pady=2)
- tk.Checkbutton(options_frame, text="Współdziel natywne biblioteki", variable=shared_natives,
- bg=BG_COLOR, fg=FG_COLOR, selectcolor=BG_COLOR, activebackground=BG_COLOR,
- font=("Segoe UI", 9)).pack(anchor="w", pady=2)
- btn_frame = ttk.Frame(frame)
- btn_frame.pack(fill="x", pady=(15, 0))
- ttk.Button(btn_frame, text="Anuluj", command=window.destroy, width=15).pack(side="right", padx=5)
- ttk.Button(btn_frame, text="Zapisz", command=lambda: [
- update_instance(version, {
- "username": username_entry.get(),
- "memory": memory_spin.get(),
- "java_path": java_paths[int(java_combo.current())][0] if java_combo.current() != -1 else current_java,
- "shared_assets": shared_assets.get(),
- "shared_libraries": shared_libs.get(),
- "shared_natives": shared_natives.get()
- }),
- window.destroy()
- ]).pack(side="right", padx=5)
- def update_instance(version, settings):
- instance = instances[version]
- instance["settings"] = settings
- info = get_version_info(version)
- if info:
- version_dir = instance["path"]
- bat_path = os.path.join(version_dir, "start.bat")
- classpath = f"{version}.jar"
- libraries_dir = LIBRARIES_DIR if settings.get("shared_libraries", True) else os.path.join(version_dir, "libraries")
- for lib in info.get("libraries", []):
- if "downloads" in lib and "artifact" in lib["downloads"]:
- lib_path = lib["downloads"]["artifact"]["path"].replace("/", os.sep)
- classpath += f";{os.path.join(libraries_dir, lib_path)}"
- assets_path = ASSETS_DIR if settings.get("shared_assets", True) else os.path.join(version_dir, "assets")
- natives_path = NATIVES_DIR if settings.get("shared_natives", True) else os.path.join(version_dir, "natives")
- java_path = settings.get("java_path", instance.get("java_path", ""))
- asset_index = info.get("assetIndex", {}).get("id", version)
- with open(bat_path, "w", encoding="utf-8") as f:
- if is_new_launcher(version):
- f.write(f'@echo off\n')
- f.write(f'title Minecraft {version}\n')
- f.write(f'"{java_path}" -Xmx{settings["memory"]}G -Djava.library.path="{natives_path}" -Dorg.lwjgl.util.Debug=true -cp "{classpath}" net.minecraft.client.main.Main ')
- f.write(f'--username {settings["username"]} --version {version} --gameDir . ')
- f.write(f'--assetsDir "{assets_path}" --assetIndex {asset_index} ')
- f.write(f'--accessToken null --uuid 0 --userType legacy\n')
- f.write(f'pause\n')
- else:
- f.write(f'@echo off\n')
- f.write(f'title Minecraft {version}\n')
- f.write(f'"{java_path}" -Xmx{settings["memory"]}G -cp "{version}.jar" net.minecraft.LauncherFrame {settings["username"]} player_session_id\n')
- f.write(f'pause\n')
- save_config()
- log_to_console(console, f"Instancja {version} zaktualizowana", "SUCCESS")
- refresh_instances()
- def show_download():
- frame = ttk.Frame(content_frame)
- frame.pack(fill="both", expand=True)
- ttk.Label(frame, text="Pobierz nową wersję Minecraft", font=("Segoe UI", 14, "bold")).pack(pady=(0, 15))
- form_frame = ttk.Frame(frame)
- form_frame.pack(fill="both", expand=True)
- ttk.Label(form_frame, text="Filtry wersji:").grid(row=0, column=0, sticky="w", pady=(0, 5))
- filters_frame = ttk.Frame(form_frame)
- filters_frame.grid(row=0, column=1, sticky="w", pady=(0, 5))
- tk.Checkbutton(filters_frame, text="Snapshoty", variable=snapshots_var, bg=BG_COLOR, fg=FG_COLOR,
- selectcolor=BG_COLOR, activebackground=BG_COLOR, font=("Segoe UI", 9),
- command=lambda: [save_config(), refresh_version_combo(combo, version_var)]).pack(anchor="w", pady=2)
- tk.Checkbutton(filters_frame, text="Release", variable=releases_var, bg=BG_COLOR, fg=FG_COLOR,
- selectcolor=BG_COLOR, activebackground=BG_COLOR, font=("Segoe UI", 9),
- command=lambda: [save_config(), refresh_version_combo(combo, version_var)]).pack(anchor="w", pady=2)
- tk.Checkbutton(filters_frame, text="Alpha", variable=alpha_var, bg=BG_COLOR, fg=FG_COLOR,
- selectcolor=BG_COLOR, activebackground=BG_COLOR, font=("Segoe UI", 9),
- command=lambda: [save_config(), refresh_version_combo(combo, version_var)]).pack(anchor="w", pady=2)
- tk.Checkbutton(filters_frame, text="Beta", variable=beta_var, bg=BG_COLOR, fg=FG_COLOR,
- selectcolor=BG_COLOR, activebackground=BG_COLOR, font=("Segoe UI", 9),
- command=lambda: [save_config(), refresh_version_combo(combo, version_var)]).pack(anchor="w", pady=2)
- ttk.Label(form_frame, text="Wersja Minecrafta:").grid(row=1, column=0, sticky="w", pady=(10, 5))
- version_var = tk.StringVar()
- versions = get_versions()
- combo = ttk.Combobox(form_frame, textvariable=version_var, state="readonly", values=versions)
- combo.grid(row=1, column=1, sticky="ew", pady=(10, 5), padx=(5, 0))
- if versions and pending_version in versions:
- combo.set(pending_version)
- elif versions:
- combo.current(0)
- else:
- messagebox.showwarning("Uwaga", "Włącz przynajmniej jeden filtr wersji (Snapshoty, Release, Alpha, Beta)!")
- console_frame = ttk.Frame(frame)
- console_frame.pack(fill="both", expand=True, pady=(15, 0))
- global console
- console = scrolledtext.ScrolledText(
- console_frame, height=10, wrap=tk.WORD, bg=CONSOLE_BG, fg=CONSOLE_FG,
- state="disabled", font=("Consolas", 9)
- )
- console.pack(fill="both", expand=True)
- btn_frame = ttk.Frame(frame)
- btn_frame.pack(fill="x", pady=(15, 0))
- ttk.Button(btn_frame, text="Pobierz", command=lambda: start_download({
- "username": pending_instance_settings.get("username", username_var.get()),
- "memory": pending_instance_settings.get("memory", memory_var.get()),
- "java_path": pending_instance_settings.get("java_path", ""),
- "shared_assets": pending_instance_settings.get("shared_assets", shared_assets_var.get()),
- "shared_libraries": pending_instance_settings.get("shared_libraries", shared_libraries_var.get()),
- "shared_natives": pending_instance_settings.get("shared_natives", shared_natives_var.get())
- }, version_var.get()) if version_var.get() else messagebox.showwarning("Uwaga", "Wybierz wersję!"), width=15).pack()
- def start_download(settings, version):
- global download_thread, download_active
- if download_active:
- messagebox.showwarning("Uwaga", "Pobieranie już w toku!")
- return
- if not version:
- messagebox.showwarning("Uwaga", "Wybierz wersję!")
- return
- download_active = True
- download_thread = threading.Thread(
- target=download_version,
- args=(version, settings, console),
- daemon=True
- )
- download_thread.start()
- def show_settings():
- frame = ttk.Frame(content_frame)
- frame.pack(fill="both", expand=True)
- ttk.Label(frame, text="Ustawienia Launchera", font=("Segoe UI", 14, "bold")).pack(pady=(0, 15))
- form_frame = ttk.Frame(frame)
- form_frame.pack(fill="both", expand=True)
- ttk.Label(form_frame, text="Domyślna nazwa użytkownika:").grid(row=0, column=0, sticky="w", pady=(0, 5))
- ttk.Entry(form_frame, textvariable=username_var).grid(row=0, column=1, sticky="ew", pady=(0, 5), padx=(5, 0))
- ttk.Label(form_frame, text="Domyślna pamięć RAM (GB):").grid(row=1, column=0, sticky="w", pady=(10, 5))
- memory_spin = tk.Spinbox(form_frame, from_=1, to=16, textvariable=memory_var, width=5,
- bg="#333333", fg=FG_COLOR, highlightthickness=0)
- memory_spin.grid(row=1, column=1, sticky="w", pady=(10, 5), padx=(5, 0))
- options_frame = ttk.Frame(form_frame)
- options_frame.grid(row=2, column=0, columnspan=2, sticky="ew", pady=(10, 5))
- tk.Checkbutton(options_frame, text="Współdziel assets między instancjami", variable=shared_assets_var,
- bg=BG_COLOR, fg=FG_COLOR, selectcolor=BG_COLOR, activebackground=BG_COLOR,
- font=("Segoe UI", 9)).pack(anchor="w", pady=2)
- tk.Checkbutton(options_frame, text="Współdziel biblioteki między instancjami", variable=shared_libraries_var,
- bg=BG_COLOR, fg=FG_COLOR, selectcolor=BG_COLOR, activebackground=BG_COLOR,
- font=("Segoe UI", 9)).pack(anchor="w", pady=2)
- tk.Checkbutton(options_frame, text="Współdziel natywne biblioteki między instancjami", variable=shared_natives_var,
- bg=BG_COLOR, fg=FG_COLOR, selectcolor=BG_COLOR, activebackground=BG_COLOR,
- font=("Segoe UI", 9)).pack(anchor="w", pady=2)
- ttk.Label(form_frame, text="Domyślne filtry wersji:").grid(row=3, column=0, sticky="w", pady=(10, 5))
- filters_frame = ttk.Frame(form_frame)
- filters_frame.grid(row=3, column=1, sticky="w", pady=(10, 5))
- tk.Checkbutton(filters_frame, text="Snapshoty", variable=snapshots_var, bg=BG_COLOR, fg=FG_COLOR,
- selectcolor=BG_COLOR, activebackground=BG_COLOR, font=("Segoe UI", 9),
- command=save_config).pack(anchor="w", pady=2)
- tk.Checkbutton(filters_frame, text="Release", variable=releases_var, bg=BG_COLOR, fg=FG_COLOR,
- selectcolor=BG_COLOR, activebackground=BG_COLOR, font=("Segoe UI", 9),
- command=save_config).pack(anchor="w", pady=2)
- tk.Checkbutton(filters_frame, text="Alpha", variable=alpha_var, bg=BG_COLOR, fg=FG_COLOR,
- selectcolor=BG_COLOR, activebackground=BG_COLOR, font=("Segoe UI", 9),
- command=save_config).pack(anchor="w", pady=2)
- tk.Checkbutton(filters_frame, text="Beta", variable=beta_var, bg=BG_COLOR, fg=FG_COLOR,
- selectcolor=BG_COLOR, activebackground=BG_COLOR, font=("Segoe UI", 9),
- command=save_config).pack(anchor="w", pady=2)
- btn_frame = ttk.Frame(frame)
- btn_frame.pack(fill="x", pady=(15, 0))
- ttk.Button(btn_frame, text="Zapisz ustawienia", command=save_config, width=20).pack()
- def show_console():
- frame = ttk.Frame(content_frame)
- frame.pack(fill="both", expand=True)
- ttk.Label(frame, text="Konsola Launchera", font=("Segoe UI", 14, "bold")).pack(pady=(0, 15))
- console_frame = ttk.Frame(frame)
- console_frame.pack(fill="both", expand=True)
- global console
- console = scrolledtext.ScrolledText(
- console_frame, height=20, wrap=tk.WORD, bg=CONSOLE_BG, fg=CONSOLE_FG,
- state="disabled", font=("Consolas", 9)
- )
- console.pack(fill="both", expand=True)
- btn_frame = ttk.Frame(frame)
- btn_frame.pack(fill="x", pady=(10, 0))
- ttk.Button(btn_frame, text="Kopiuj", command=lambda: copy_console(console), width=15).pack(side="left", padx=5)
- ttk.Button(btn_frame, text="Wyczyść", command=lambda: clear_console(console), width=15).pack(side="left", padx=5)
- def refresh_version_combo(combo, version_var):
- versions = get_versions()
- combo['values'] = versions
- if versions:
- version_var.set(versions[0])
- else:
- version_var.set("")
- messagebox.showwarning("Uwaga", "Włącz przynajmniej jeden filtr wersji (Snapshoty, Release, Alpha, Beta)!")
- print(f"{Fore.LIGHTCYAN_EX}{Fore.LIGHTCYAN_EX}Inicjalizacja zakończona, uruchamiam UI...")
- switch_tab("Instancje")
- root.mainloop()
- except Exception as e:
- print(f"{Fore.LIGHTCYAN_EX}CRASH: {e}")
- with open(os.path.join(LOGS_DIR, "crash.log"), "a", encoding="utf-8") as f:
- f.write(f"[{datetime.now()}] CRASH: {e}\n")
- raise
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement