This commit is contained in:
neoapps-dev 2026-04-02 16:10:12 +03:00
parent 535735fcb2
commit 340f636b8e
14 changed files with 7776 additions and 1242 deletions

View file

@ -52,39 +52,12 @@ jobs:
- name: install frontend dependencies
run: pnpm install
- name: Build and create DMG for macOS
- name: build and fix macOS
if: matrix.platform == 'macos-latest'
run: |
pnpm build
cd src-tauri
cargo build --release --target ${{ matrix.args }}
cd ..
TARGET_ARCH=${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}
mkdir -p "src-tauri/target/$TARGET_ARCH/release/bundle/macos/Emerald Legacy Launcher.app/Contents/MacOS"
mkdir -p "src-tauri/target/$TARGET_ARCH/release/bundle/macos/Emerald Legacy Launcher.app/Contents/Resources"
cp "src-tauri/target/$TARGET_ARCH/release/emerald-legacy-launcher" "src-tauri/target/$TARGET_ARCH/release/bundle/macos/Emerald Legacy Launcher.app/Contents/MacOS/"
printf '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n <key>CFBundleExecutable</key>\n <string>emerald-legacy-launcher</string>\n <key>CFBundleIdentifier</key>\n <string>com.emerald.legacy</string>\n <key>CFBundleName</key>\n <string>Emerald Legacy Launcher</string>\n <key>CFBundleVersion</key>\n <string>1.0.0</string>\n <key>CFBundleShortVersionString</key>\n <string>1.0.0</string>\n <key>CFBundlePackageType</key>\n <string>APPL</string>\n <key>NSHighResolutionCapable</key>\n <true/>\n <key>LSApplicationCategoryType</key>\n <string>public.app-category.games</string>\n</dict>\n</plist>\n' > "src-tauri/target/$TARGET_ARCH/release/bundle/macos/Emerald Legacy Launcher.app/Contents/Info.plist"
if [ -f "src-tauri/icons/icon.icns" ]; then
cp src-tauri/icons/icon.icns "src-tauri/target/$TARGET_ARCH/release/bundle/macos/Emerald Legacy Launcher.app/Contents/Resources/"
fi
chmod +x "src-tauri/target/$TARGET_ARCH/release/bundle/macos/Emerald Legacy Launcher.app/Contents/MacOS/emerald-legacy-launcher"
cd "src-tauri/target/$TARGET_ARCH/release/bundle/macos"
hdiutil create -volname "Emerald Legacy Launcher" -srcfolder "Emerald Legacy Launcher.app" -ov -format UDZO "Emerald Legacy Launcher.dmg"
mkdir -p "$GITHUB_WORKSPACE/src-tauri/target/release/bundle/dmg/"
mv "Emerald Legacy Launcher.dmg" "$GITHUB_WORKSPACE/src-tauri/target/release/bundle/dmg/"
- name: Build with tauri-action for Windows and Linux
if: matrix.platform != 'macos-latest'
uses: tauri-apps/tauri-action@v0
pnpm tauri build ${{ matrix.args }}
pnpm run post-build:macos
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -92,166 +65,48 @@ jobs:
releaseName: 'Emerald Nightly'
releaseBody: |
# Emerald Legacy Launcher (Nightly)
## 📥 What to download?
### 🐧 GNU/Linux
- **RHEL/Fedora**: `Emerald.Legacy.Launcher-*.rpm`
- **Debian/Ubuntu**: `Emerald.Legacy.Launcher-*.deb`
- **Universal**: `Emerald.Legacy.Launcher-*.AppImage`
- **Flatpak**: `io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.flatpak`
### 🍎 macOS
- **Intel Mac**: `Emerald.Legacy.Launcher_*.x64.dmg`
- **M-series Mac**: `Emerald.Legacy.Launcher_*.aarch64.dmg`
### 🪟 Windows
- **Setup Installer**: `Emerald.Legacy.Launcher-*.exe`
- **MSI Installer**: `Emerald.Legacy.Launcher-*.msi`
# What to download?
- `Emerald.Legacy.Launcher-*.rpm` for GNU/Linux (RHEL)
- `Emerald.Legacy.Launcher-*.deb` for GNU/Linux (Debian+Ubuntu)
- `Emerald.Legacy.Launcher-*.AppImage` for GNU/Linux (Universal)
- `Emerald.Legacy.Launcher-*_x64.dmg` for macOS (Intel)
- `Emerald.Legacy.Launcher-*_aarch64.dmg` for macOS (M-series)
- `Emerald.Legacy.Launcher-*.exe` for Windows (Setup)
- `Emerald.Legacy.Launcher-*.msi` for Windows (Setup)
---
## ⚠️ Windows SmartScreen
# Windows SmartScreen
This software is completely safe. Because the launcher is unsigned, you will see a "Windows protected your PC" window. To proceed:
1. Click the **"More info"** link under the main text.
2. Click the **"Run anyway"** button that appears.
## 🍎 macOS Installation
Download the DMG file, open it, and drag the app to Applications folder.
If you see "app damaged" error, right-click the app → Open → confirm Open.
Or run: `xattr -cr "/Applications/Emerald Legacy Launcher.app"`
---
# macOS "Damaged" Error Fix
The macOS builds now include automatic fixes for Gatekeeper quarantine issues. The app should launch without "application is damaged" errors.
releaseDraft: false
prerelease: true
args: ${{ matrix.args }}
- name: Upload all artifacts to release
uses: softprops/action-gh-release@v2
with:
files: |
src-tauri/target/release/bundle/deb/*.deb
src-tauri/target/release/bundle/appimage/*.AppImage
src-tauri/target/release/bundle/rpm/*.rpm
src-tauri/target/release/bundle/msi/*.msi
src-tauri/target/release/bundle/nsis/*.exe
tag_name: nightly
name: 'Emerald Nightly'
body: |
# Emerald Legacy Launcher (Nightly)
# What to download?
- `Emerald.Legacy.Launcher-*.rpm` for GNU/Linux (RHEL)
- `Emerald.Legacy.Launcher-*.deb` for GNU/Linux (Debian+Ubuntu)
- `Emerald.Legacy.Launcher-*.AppImage` for GNU/Linux (Universal)
- `Emerald Legacy Launcher*.dmg` for macOS (Intel + M-series)
- `Emerald.Legacy.Launcher-*.exe` for Windows (Setup)
- `Emerald.Legacy.Launcher-*.msi` for Windows (Setup)
- `io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.flatpak` for GNU/Linux (Flatpak)
---
# Windows SmartScreen
This software is completely safe. Because the launcher is unsigned, you will see a "Windows protected your PC" window. To proceed:
1. Click the **"More info"** link under the main text.
2. Click the **"Run anyway"** button that appears.
---
# macOS Installation
Download the DMG file, open it, and drag the app to Applications folder.
If you see "app damaged" error, right-click the app → Open → confirm Open.
Or run: `xattr -cr "/Applications/Emerald Legacy Launcher.app"`
draft: false
prerelease: true
- name: Upload macOS DMGs to release
if: matrix.platform == 'macos-latest'
uses: softprops/action-gh-release@v2
with:
files: src-tauri/target/release/bundle/dmg/*.dmg
tag_name: nightly
name: 'Emerald Nightly'
body: |
# Emerald Legacy Launcher (Nightly)
# What to download?
- `Emerald.Legacy.Launcher-*.rpm` for GNU/Linux (RHEL)
- `Emerald.Legacy.Launcher-*.deb` for GNU/Linux (Debian+Ubuntu)
- `Emerald.Legacy.Launcher-*.AppImage` for GNU/Linux (Universal)
- `Emerald Legacy Launcher*.dmg` for macOS (Intel + M-series)
- `Emerald.Legacy.Launcher-*.exe` for Windows (Setup)
- `Emerald.Legacy.Launcher-*.msi` for Windows (Setup)
- `io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.flatpak` for GNU/Linux (Flatpak)
---
# Windows SmartScreen
This software is completely safe. Because the launcher is unsigned, you will see a "Windows protected your PC" window. To proceed:
1. Click the **"More info"** link under the main text.
2. Click the **"Run anyway"** button that appears.
---
# macOS Installation
Download the DMG file, open it, and drag the app to Applications folder.
If you see "app damaged" error, right-click the app → Open → confirm Open.
Or run: `xattr -cr "/Applications/Emerald Legacy Launcher.app"`
draft: false
prerelease: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
nightly-flatpak:
runs-on: ubuntu-latest
permissions:
contents: write
needs: nightly-tauri
needs: nightly-tauri # Wait for Tauri release to be created
container:
image: bilelmoussaoui/flatpak-github-actions:freedesktop-23.08
options: --privileged
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: install dependencies
run: |
sudo apt-get update
sudo apt-get install -y flatpak flatpak-builder
- name: setup flathub
run: |
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
sudo flatpak install -y flathub org.gnome.Sdk//48 org.gnome.Platform//48 org.freedesktop.Sdk.Extension.node20//24.08 org.freedesktop.Sdk.Extension.rust-stable//24.08
sudo flatpak update
- name: setup flatpak
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
submodules: true
- uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with:
bundle: io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.flatpak
manifest-path: flatpak/io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.yml
cache-key: flatpak-builder-${{ github.sha }}
build-bundle: true
repository-url: https://flathub.org/repo/flathub.flatpakrepo
repository-name: flathub
- name: Upload flatpak to release
uses: softprops/action-gh-release@v2
- uses: softprops/action-gh-release@v2
with:
files: "*.flatpak"
files: io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.flatpak
tag_name: nightly
name: 'Emerald Nightly'
body: |
# Emerald Legacy Launcher (Nightly)
# What to download?
- `Emerald.Legacy.Launcher-*.rpm` for GNU/Linux (RHEL)
- `Emerald.Legacy.Launcher-*.deb` for GNU/Linux (Debian+Ubuntu)
- `Emerald.Legacy.Launcher-*.AppImage` for GNU/Linux (Universal)
- `Emerald Legacy Launcher*.dmg` for macOS (Intel + M-series)
- `Emerald.Legacy.Launcher-*.exe` for Windows (Setup)
- `Emerald.Legacy.Launcher-*.msi` for Windows (Setup)
- `io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.flatpak` for GNU/Linux (Flatpak)
---
# Windows SmartScreen
This software is completely safe. Because the launcher is unsigned, you will see a "Windows protected your PC" window. To proceed:
1. Click the **"More info"** link under the main text.
2. Click the **"Run anyway"** button that appears.
---
# macOS Installation
Download the DMG file, open it, and drag the app to Applications folder.
If you see "app damaged" error, right-click the app → Open → confirm Open.
Or run: `xattr -cr "/Applications/Emerald Legacy Launcher.app"`
draft: false
prerelease: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -15,28 +15,20 @@ jobs:
args: '--target aarch64-apple-darwin'
- platform: 'macos-latest'
args: '--target x86_64-apple-darwin'
- platform: 'ubuntu-22.04'
args: ''
- platform: 'windows-latest'
args: ''
# - platform: 'ubuntu-22.04'
# args: ''
# - platform: 'windows-latest'
# args: ''
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- name: Extract version
id: get_version
shell: bash
run: |
VERSION=$(node -p "require('./package.json').version")
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
echo "APP_VERSION=$VERSION" >> $GITHUB_ENV
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libudev-dev
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
- name: setup pnpm
uses: pnpm/action-setup@v4
@ -60,220 +52,61 @@ jobs:
- name: install frontend dependencies
run: pnpm install
- name: Build and create artifacts for macOS
- name: Create PKG with post-install script
if: matrix.platform == 'macos-latest'
run: |
# Build the app once
pnpm build
cd src-tauri
cargo build --release --target ${{ matrix.args }}
cd ..
# Setup target architecture name
TARGET_ARCH=${{ matrix.args == '--target aarch64-apple-darwin' && 'aarch64-apple-darwin' || 'x86_64-apple-darwin' }}
# Prepare paths for .app bundle
mkdir -p "src-tauri/target/$TARGET_ARCH/release/bundle/macos/Emerald Legacy Launcher.app/Contents/MacOS"
mkdir -p "src-tauri/target/$TARGET_ARCH/release/bundle/macos/Emerald Legacy Launcher.app/Contents/Resources"
cp "src-tauri/target/$TARGET_ARCH/release/emerald-legacy-launcher" "src-tauri/target/$TARGET_ARCH/release/bundle/macos/Emerald Legacy Launcher.app/Contents/MacOS/"
printf '<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n <key>CFBundleExecutable</key>\n <string>emerald-legacy-launcher</string>\n <key>CFBundleIdentifier</key>\n <string>com.emerald.legacy</string>\n <key>CFBundleName</key>\n <string>Emerald Legacy Launcher</string>\n <key>CFBundleVersion</key>\n <string>${{ steps.get_version.outputs.VERSION }}</string>\n <key>CFBundleShortVersionString</key>\n <string>${{ steps.get_version.outputs.VERSION }}</string>\n <key>CFBundlePackageType</key>\n <string>APPL</string>\n <key>NSHighResolutionCapable</key>\n <true/>\n <key>LSApplicationCategoryType</key>\n <string>public.app-category.games</string>\n</dict>\n</plist>\n' > "src-tauri/target/$TARGET_ARCH/release/bundle/macos/Emerald Legacy Launcher.app/Contents/Info.plist"
if [ -f "src-tauri/icons/icon.icns" ]; then
cp src-tauri/icons/icon.icns "src-tauri/target/$TARGET_ARCH/release/bundle/macos/Emerald Legacy Launcher.app/Contents/Resources/"
fi
chmod +x "src-tauri/target/$TARGET_ARCH/release/bundle/macos/Emerald Legacy Launcher.app/Contents/MacOS/emerald-legacy-launcher"
# Create PKG (optional, using the built .app)
# Create temporary directory for PKG creation
mkdir -p pkg_temp/scripts
cp scripts/postinstall.sh pkg_temp/scripts/
pkgbuild --root "src-tauri/target/$TARGET_ARCH/release/bundle/macos" \
# Build the app first
pnpm tauri build -- ${{ matrix.args }}
# Find the built app
APP_PATH=$(find src-tauri/target/release/bundle/macos/ -name "*.app" | head -1)
APP_NAME=$(basename "$APP_PATH")
# Create PKG with post-install script
pkgbuild --root "$APP_PATH/.." \
--install-location /Applications \
--scripts pkg_temp/scripts \
--identifier "com.emerald.legacy" \
--version "${{ steps.get_version.outputs.VERSION }}" \
--version "1.0.0" \
--install-location "/Applications" \
--root "$APP_PATH" \
"Emerald-Legacy-Launcher.pkg"
# Create DMG
cd "src-tauri/target/$TARGET_ARCH/release/bundle/macos"
hdiutil create -volname "Emerald Legacy Launcher" -srcfolder "Emerald Legacy Launcher.app" -ov -format UDZO "Emerald Legacy Launcher.dmg"
# Move artifacts to final locations
mkdir -p "$GITHUB_WORKSPACE/src-tauri/target/release/bundle/dmg/"
mv "Emerald Legacy Launcher.dmg" "$GITHUB_WORKSPACE/src-tauri/target/release/bundle/dmg/"
mkdir -p "$GITHUB_WORKSPACE/src-tauri/target/release/bundle/macos/"
mv "$GITHUB_WORKSPACE/Emerald-Legacy-Launcher.pkg" "$GITHUB_WORKSPACE/src-tauri/target/release/bundle/macos/"
- name: Build with tauri-action for Windows and Linux
if: matrix.platform != 'macos-latest'
uses: tauri-apps/tauri-action@v0
# Move PKG to bundle directory
mkdir -p src-tauri/target/release/bundle/macos/
mv "Emerald-Legacy-Launcher.pkg" src-tauri/target/release/bundle/macos/
- uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tagName: v${{ steps.get_version.outputs.VERSION }}
releaseName: 'Emerald v${{ steps.get_version.outputs.VERSION }}'
releaseBody: |
# Emerald Legacy Launcher v${{ steps.get_version.outputs.VERSION }}
## 📥 What to download?
### 🐧 GNU/Linux
- **RHEL/Fedora**: `Emerald.Legacy.Launcher-*.rpm`
- **Debian/Ubuntu**: `Emerald.Legacy.Launcher-*.deb`
- **Universal**: `Emerald.Legacy.Launcher-*.AppImage`
- **Flatpak**: `io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.flatpak`
### 🍎 macOS
- **Intel Mac**: `Emerald.Legacy.Launcher_*.x64.dmg`
- **M-series Mac**: `Emerald.Legacy.Launcher_*.aarch64.dmg`
### 🪟 Windows
- **Setup Installer**: `Emerald.Legacy.Launcher-*.exe`
- **MSI Installer**: `Emerald.Legacy.Launcher-*.msi`
---
## ⚠️ Windows SmartScreen
This software is completely safe. Because the launcher is unsigned, you will see a "Windows protected your PC" window. To proceed:
1. Click the **"More info"** link under the main text.
2. Click the **"Run anyway"** button that appears.
## 🍎 macOS Installation
Download the DMG file, open it, and drag the app to Applications folder.
If you see "app damaged" error, right-click the app → Open → confirm Open.
Or run: `xattr -cr "/Applications/Emerald Legacy Launcher.app"`
tagName: v__VERSION__
releaseName: 'Emerald v__VERSION__'
releaseBody: '*pls edit me*'
releaseDraft: true
prerelease: false
args: ${{ matrix.args }}
- name: Upload all artifacts to release
if: matrix.platform != 'macos-latest'
uses: softprops/action-gh-release@v2
with:
files: |
src-tauri/target/release/bundle/deb/*.deb
src-tauri/target/release/bundle/appimage/*.AppImage
src-tauri/target/release/bundle/rpm/*.rpm
src-tauri/target/release/bundle/msi/*.msi
src-tauri/target/release/bundle/nsis/*.exe
tag_name: v${{ steps.get_version.outputs.VERSION }}
name: 'Emerald v${{ steps.get_version.outputs.VERSION }}'
body: |
# Emerald Legacy Launcher v${{ steps.get_version.outputs.VERSION }}
## 📥 What to download?
### 🐧 GNU/Linux
- **RHEL/Fedora**: `Emerald.Legacy.Launcher-*.rpm`
- **Debian/Ubuntu**: `Emerald.Legacy.Launcher-*.deb`
- **Universal**: `Emerald.Legacy.Launcher-*.AppImage`
- **Flatpak**: `io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.flatpak`
### 🍎 macOS
- **Intel Mac**: `Emerald.Legacy.Launcher_*.x64.dmg`
- **M-series Mac**: `Emerald.Legacy.Launcher_*.aarch64.dmg`
### 🪟 Windows
- **Setup Installer**: `Emerald.Legacy.Launcher-*.exe`
- **MSI Installer**: `Emerald.Legacy.Launcher-*.msi`
---
## ⚠️ Windows SmartScreen
This software is completely safe. Because the launcher is unsigned, you will see a "Windows protected your PC" window. To proceed:
1. Click the **"More info"** link under the main text.
2. Click the **"Run anyway"** button that appears.
## 🍎 macOS Installation
Download the DMG file, open it, and drag the app to Applications folder.
If you see "app damaged" error, right-click the app → Open → confirm Open.
Or run: `xattr -cr "/Applications/Emerald Legacy Launcher.app"`
draft: true
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload macOS DMGs to release
if: matrix.platform == 'macos-latest'
uses: softprops/action-gh-release@v2
with:
files: |
src-tauri/target/release/bundle/dmg/*.dmg
src-tauri/target/release/bundle/macos/*.pkg
tag_name: v${{ steps.get_version.outputs.VERSION }}
name: 'Emerald v${{ steps.get_version.outputs.VERSION }}'
body: |
# Emerald Legacy Launcher v${{ steps.get_version.outputs.VERSION }}
## 📥 What to download?
### 🐧 GNU/Linux
- **RHEL/Fedora**: `Emerald.Legacy.Launcher-*.rpm`
- **Debian/Ubuntu**: `Emerald.Legacy.Launcher-*.deb`
- **Universal**: `Emerald.Legacy.Launcher-*.AppImage`
- **Flatpak**: `io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.flatpak`
### 🍎 macOS
- **Intel Mac**: `Emerald.Legacy.Launcher_*.x64.dmg`
- **M-series Mac**: `Emerald.Legacy.Launcher_*.aarch64.dmg`
### 🪟 Windows
- **Setup Installer**: `Emerald.Legacy.Launcher-*.exe`
- **MSI Installer**: `Emerald.Legacy.Launcher-*.msi`
---
## ⚠️ Windows SmartScreen
This software is completely safe. Because the launcher is unsigned, you will see a "Windows protected your PC" window. To proceed:
1. Click the **"More info"** link under the main text.
2. Click the **"Run anyway"** button that appears.
## 🍎 macOS Installation
Download the DMG file, open it, and drag the app to Applications folder.
If you see "app damaged" error, right-click the app → Open → confirm Open.
Or run: `xattr -cr "/Applications/Emerald Legacy Launcher.app"`
draft: true
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-flatpak:
runs-on: ubuntu-latest
permissions:
contents: write
needs: publish-tauri
needs: publish-tauri # Wait for Tauri release to be created
container:
image: bilelmoussaoui/flatpak-github-actions:freedesktop-23.08
options: --privileged
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: install dependencies
run: |
sudo apt-get update
sudo apt-get install -y flatpak flatpak-builder
- name: setup flathub
run: |
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
sudo flatpak install -y flathub org.gnome.Sdk//48 org.gnome.Platform//48 org.freedesktop.Sdk.Extension.node20//24.08 org.freedesktop.Sdk.Extension.rust-stable//24.08
sudo flatpak update
- name: setup flatpak
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
submodules: true
- uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with:
bundle: io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.flatpak
manifest-path: flatpak/io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.yml
cache-key: flatpak-builder-${{ github.sha }}
build-bundle: true
repository-url: https://flathub.org/repo/flathub.flatpakrepo
repository-name: flathub
- uses: softprops/action-gh-release@v2
with:
files: io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.flatpak

333
README.md
View file

@ -1,13 +1,7 @@
<div align="center">
<img height="150" src="https://raw.githubusercontent.com/Emerald-Legacy-Launcher/Emerald-Legacy-Launcher/refs/heads/main/public/images/icon.png" alt="Emerald Legacy Launcher Logo">
<img height="150" src="https://raw.githubusercontent.com/Emerald-Legacy-Launcher/Emerald-Legacy-Launcher/refs/heads/main/public/images/logo.png">
<h1>Emerald Legacy Launcher</h1>
<p><strong>FOSS cross-platform launcher for Minecraft Legacy Console Edition</strong></p>
<p>
<img src="https://img.shields.io/badge/version-1.0.0-blue?style=flat-square" alt="Version">
<img src="https://img.shields.io/badge/license-GPL--3.0-green?style=flat-square" alt="License">
<img src="https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey?style=flat-square" alt="Platforms">
</p>
<p>FOSS cross-platform launcher for Minecraft Legacy Console Edition</p>
</div>
<p align="center">
@ -27,300 +21,57 @@
---
## Table of Contents
<img width="1680" height="960" alt="Screenshot" src="https://github.com/user-attachments/assets/a5dd6aa1-2200-4f08-84e5-e75a8052ba79" />
- [Overview](#overview)
- [Features](#features)
- [Screenshots](#screenshots)
- [Installation](#installation)
- [Windows](#windows)
- [macOS](#macos)
- [Linux](#linux)
- [Game Versions & Partnerships](#game-versions--partnerships)
- [Building from Source](#building-from-source)
- [Development](#development)
- [Project Structure](#project-structure)
- [Tech Stack](#tech-stack)
- [Troubleshooting](#troubleshooting)
- [Roadmap](#roadmap)
- [Acknowledgments](#acknowledgments)
- [License](#license)
### PROJECT OVERVIEW
Emerald Legacy Launcher started as a solo project to create a better way to play Legacy Console Edition. Over time, other developers joined the effort, bringing expertise from various preservation projects into one place.
**Our Philosophy:** For too long, the LCE scene has been fragmented across different, often resource-heavy launchers. Emerald was built to stop this fragmentation and centralize everything into a single, definitive hub. By avoiding bloated frameworks and utilizing a modern Rust/Tauri stack, we deliver a high-performance, cross-platform experience that uses only ~15MB of RAM, leaving all your PC's resources dedicated to the game itself.
---
## Overview
### CORE FEATURES
Emerald Legacy Launcher is a **high-performance, open-source launcher** for Minecraft Legacy Console Edition (LCE). Built to centralize the fragmented LCE scene, it provides a lightweight, unified hub for playing your favorite console versions of Minecraft on PC.
**Why Emerald?** Traditional launchers often rely on bloated frameworks, consuming excessive resources. Emerald utilizes a modern **Rust/Tauri** architecture, using only **~15MB of RAM** — leaving your PC's resources dedicated to the game itself.
The project started as a solo effort and has grown into a collaborative community project, bringing together expertise from various LCE preservation initiatives.
<table width="100%" style="border-collapse: collapse;">
<tr>
<td style="padding: 20px; border: 1px solid #333;">
<b>EASY SETUP</b><br>
An automated installation process for TU19, Legacy Evolved and 360Revived, with more versions coming in future updates.
</td>
<td style="padding: 20px; border: 1px solid #333;">
<b>RUST BACKEND</b><br>
A memory-safe backend that handles all file operations and game execution with minimal overhead.
</td>
</tr>
<tr>
<td style="padding: 20px; border: 1px solid #333;">
<b>EASY CONFIGURATION</b><br>
An integrated settings menu to change your username and manage game parameters directly through the launcher.
</td>
<td style="padding: 20px; border: 1px solid #333;">
<b>TAURI FRONTEND</b><br>
A lightweight frontend that handles the user interface and configuration management via webview.
</td>*Proudly developed by a passionate team from the LCE community.*
</tr>
</table>
---
## Features
### Core Features
| Feature | Description |
|---------|-------------|
| **Automated Setup** | One-click installation for TU19, Legacy Evolved, Revelations, and 360Revived versions |
| **Cross-Platform** | Native support for Windows, macOS (Intel & Apple Silicon), and Linux |
| **Lightweight** | Very light RAM usage thanks to Rust backend and Tauri framework |
| **Easy Configuration** | Built-in settings for username, game parameters, and profiles |
### Advanced Features
| Feature | Description |
|---------|-------------|
| **3D Skin Viewer** | Interactive skin preview using Three.js with layer support |
| **Custom Skins** | Import and manage your own skins with local storage |
| **Controller Support** | Full gamepad navigation support (keyboard fallback included) |
| **Discord Rich Presence** | Show your current activity and game status on Discord |
| **Workshop and modloader** | *(Coming Soon)* Community content and mod browser |
### [DEVELOPMENT ROADMAP](https://github.com/orgs/Emerald-Legacy-Launcher/projects/2)
Click the heading above to track progress, view active tasks, and see upcoming launcher features.
---
## Game Versions & Partnerships
Emerald Legacy Launcher integrates multiple community-driven builds of Minecraft Legacy Console Edition. Each build brings unique features and improvements to the classic LCE experience.
### Available Builds
| Build | Developer | Platform | Description |
|-------|-----------|----------|-------------|
| **[Revelations](https://github.com/itsRevela/MinecraftConsoles)** | [@itsRevela](https://github.com/itsRevela) | GitHub | Enhanced LCE with uncapped FPS, graphics fixes, hardcore hearts, and dedicated server security. Features LAN multiplayer, split-screen, and keyboard & mouse support. |
| **[360 Revived](https://github.com/BluTac10/360Revived)** | [@BluTac10](https://github.com/BluTac10) | GitHub | PC port of Xbox 360 Edition TU19 with desktop optimizations. Features keyboard & mouse, fullscreen, LAN multiplayer, dedicated server, and split-screen support. |
| **[Legacy Evolved](https://codeberg.org/piebot/LegacyEvolved)** | [@piebot](https://codeberg.org/piebot) | Codeberg | Backports newer title updates to LCE TU19 base. Currently porting TU25 (~98% complete) and TU31 (~76% complete). |
| **[Title Update 19](https://github.com/smartcmd/MinecraftConsoles)** | [@smartcmd](https://github.com/smartcmd) | GitHub | Minecraft LCE v1.6.0560.0 with compilation fixes. Base version for modding with keyboard & mouse, fullscreen, LAN multiplayer, and dedicated server support. |
### Coming Soon: Legacy Minecraft Restoration Project (LMRP)
**LMRP** will be our **first major collaboration** to bring fully functional **online mini-games** back to Legacy Console Edition. This groundbreaking project aims to:
- Restore classic LCE mini-games (Battle, Tumble, Glide)
- Preserve the authentic mini-game mechanics and maps
Stay tuned for updates on this exciting partnership! :)
> ### ACKNOWLEDGMENTS
> * <sub style="color: grey;">**The Emerald Team:** Technical development and maintenance.</sub>
> * <sub style="color: grey;">**4J Studios & Mojang:** Original creators of Legacy Console Edition.</sub>
> * <sub style="color: grey;">**smartcmd & The LCE Community:** Research and foundations for Legacy Console Edition on PC.</sub>
> * <sub style="color: grey;">**LegacyEvolved:** Backporting TUs into smartcmd</sub>
> * <sub style="color: grey;">**Tauri & Rust:** Core technologies.</sub>
---
## Screenshots
<img width="1680" alt="Emerald Legacy Launcher Screenshot" src="https://github.com/user-attachments/assets/a5dd6aa1-2200-4f08-84e5-e75a8052ba79" />
---
## Installation
### Windows
Download the latest release from [GitHub Releases](https://github.com/Emerald-Legacy-Launcher/Emerald-Legacy-Launcher/releases):
| Format | Best For |
|--------|----------|
| `.exe` (NSIS) | Standard installation with uninstaller |
| `.msi` | Enterprise/IT deployment |
**⚠️ Windows SmartScreen Warning:**
> Since the launcher is unsigned, Windows may show a "Windows protected your PC" warning. To proceed:
> 1. Click **"More info"**
> 2. Click **"Run anyway"**
### macOS
| Format | Architecture |
|--------|-------------|
| `.dmg` (x64) | Intel Macs |
| `.dmg` (aarch64) | Apple Silicon (M1/M2/M3) |
**Installation Steps:**
1. Download the appropriate DMG for your Mac
2. Open the DMG and drag the app to Applications
3. If you see "app is damaged" error:
- Right-click the app → **Open** → confirm **Open**
- Or run: `xattr -cr "/Applications/Emerald Legacy Launcher.app"`
### Linux
Multiple distribution formats available:
| Format | Distribution |
|--------|------------|
| `.deb` | Debian, Ubuntu, Linux Mint |
| `.rpm` | RHEL, Fedora, openSUSE |
| `.AppImage` | Universal (no installation required) |
| `Flatpak` | Universal with sandboxing |
**Flatpak Installation:**
```bash
flatpak install emerald.flatpak
```
**Dependencies (if building from source):**
```bash
# Ubuntu/Debian
sudo apt install libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libudev-dev
# Fedora
sudo dnf install webkit2gtk4.1-devel libappindicator-gtk3-devel librsvg2-devel patchelf systemd-devel
```
---
## Building from Source
### Requirements
- **Node.js** (LTS recommended)
- **Rust** (latest stable)
- **PNPM** (recommended) or NPM
- Platform-specific dependencies:
- Linux: `WebKit2GTK-4.1`
- macOS: WebKit (pre-installed)
- Windows: Edge WebView2 Runtime (usually pre-installed)
### Build Steps
```bash
# Clone the repository
git clone https://github.com/Emerald-Legacy-Launcher/Emerald-Legacy-Launcher.git
cd Emerald-Legacy-Launcher
# Install dependencies
pnpm install
# Development mode
pnpm tauri dev
# Production build
pnpm tauri build
```
**Flatpak Build:**
```bash
pnpm flatpak
```
---
## Development
### Project Structure
```
Emerald-Legacy-Launcher/
├── src/ # React frontend
│ ├── components/ # UI components
│ ├── context/ # React context providers
│ ├── hooks/ # Custom React hooks
│ ├── pages/ # Page components
│ ├── services/ # API/services layer
│ └── css/ # Global styles
├── src-tauri/ # Rust backend
│ ├── src/ # Rust source code
│ ├── Cargo.toml # Rust dependencies
│ └── tauri.conf.json # Tauri configuration
├── public/ # Static assets
├── flatpak/ # Flatpak build config
└── scripts/ # Build scripts
```
### Tech Stack
| Layer | Technology | Version |
|-------|-----------|---------|
| **Backend** | Rust | 2021 Edition |
| **Framework** | Tauri | v2 |
| **Frontend** | React | ^19.1.0 |
| **Language** | TypeScript | ~5.8.3 |
| **Styling** | TailwindCSS | v4 |
| **Animations** | Framer Motion | ^12.36.0 |
| **3D Rendering** | Three.js | ^0.183.2 |
| **Build Tool** | Vite | ^7.0.4 |
### Key Dependencies
**Rust Crates:**
- `tauri` — Cross-platform app framework
- `serde` — Serialization
- `reqwest` — HTTP client
- `tokio` — Async runtime
- `rfd` — Native file dialogs
**Frontend Packages:**
- `@tauri-apps/api` — Tauri JS API
- `tauri-plugin-drpc` — Discord Rich Presence
- `tauri-plugin-gamepad-api` — Controller support
---
## Troubleshooting
### macOS "App is Damaged" Error
```bash
# Remove quarantine attributes
xattr -cr /path/to/Emerald\ Legacy\ Launcher.app
```
### Linux WebView Issues
Ensure WebKit2GTK-4.1 is installed:
```bash
# Check installation
pkg-config --modversion webkit2gtk-4.1
# Reinstall if needed
sudo apt install --reinstall libwebkit2gtk-4.1-0
```
### Game Not Launching
1. Verify game files are properly installed via the launcher
2. Check that Wine/Proton is installed (Linux only)
3. Check that Wine/GPTK3 are installed (macOS only)
4. Ensure your GPU drivers are up to date
### Controller Not Detected
- Connect controller before launching the launcher
- Xbox and PlayStation controllers are best supported
---
## Roadmap
Track our progress and upcoming features on the [Development Roadmap](https://github.com/orgs/Emerald-Legacy-Launcher/projects/2).
**Planned Features:**
- [ ] Workshop content browser
- [ ] Additional TU versions support
- [ ] Enhanced mod support
- [ ] Cloud sync for settings/skins
- [ ] Auto-updater integration
---
## Acknowledgments
*Proudly developed by a passionate team from the LCE community.*
- **The Emerald Team** — Technical development and maintenance
- **4J Studios & Mojang** — Original creators of Legacy Console Edition
- **smartcmd & The LCE Community** — Research and foundations for LCE on PC
- **Tauri & Rust Communities** — Core technologies and ecosystem
---
## License
This project is licensed under the **[GNU GPL v3 License](LICENSE)**.
You are free to:
- **Use** — Use the launcher for any purpose
- **Study** — Access and study the source code
- **Share** — Redistribute copies
- **Improve** — Submit improvements and modifications
See `LICENSE` file for full terms.
***This project is licensed under the [GNU GPL v3 License](LICENSE)***

7350
changes.patch Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 KiB

View file

@ -1,98 +0,0 @@
import { motion } from "framer-motion";
import { useState, useEffect } from "react";
export default function SpecialThanksModal({
isOpen,
onClose,
playSfx,
}: any) {
const [focusIndex, setFocusIndex] = useState(0);
const contributors = [
{ name: "smartcmd & LCE Community", desc: "Research & Foundations" },
{ name: "Andi_pog & AFanFromWalmart", desc: "Project Testers" }
];
useEffect(() => {
if (!isOpen) {
setFocusIndex(0);
return;
}
const handleKey = (e: KeyboardEvent) => {
if (e.key === "Escape") {
playSfx("close_click.wav");
onClose();
} else if (e.key === "ArrowDown" || e.key === "Tab") {
e.preventDefault();
setFocusIndex((prev) => (prev + 1) % (contributors.length + 1));
} else if (e.key === "ArrowUp") {
e.preventDefault();
setFocusIndex((prev) => (prev - 1 + (contributors.length + 1)) % (contributors.length + 1));
} else if (e.key === "Enter") {
if (focusIndex === contributors.length) {
playSfx("close_click.wav");
onClose();
}
}
};
window.addEventListener("keydown", handleKey);
return () => window.removeEventListener("keydown", handleKey);
}, [isOpen, focusIndex]);
if (!isOpen) return null;
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="absolute inset-0 z-[110] flex items-center justify-center bg-black/80 backdrop-blur-sm outline-none border-none"
>
<div
className="relative w-[400px] p-6 flex flex-col items-center shadow-2xl"
style={{
backgroundImage: "url('/images/frame_background.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
<h2 className="text-[#FFFF55] text-2xl mc-text-shadow mb-4 border-b-2 border-[#373737] pb-2 w-full text-center uppercase">
Special Thanks
</h2>
<div className="flex flex-col gap-2 w-full items-center max-h-[320px] overflow-y-auto overflow-x-hidden scrollbar-hide py-2">
{contributors.map((item, idx) => (
<div
key={item.name}
onMouseEnter={() => setFocusIndex(idx)}
className={`w-[90%] p-2 flex flex-col items-center justify-center mc-text-shadow transition-transform outline-none border-none bg-transparent ${focusIndex === idx ? "scale-105 text-[#FFFF55]" : "opacity-80 text-white"}`}
>
<span className="text-xl">
{item.name}
</span>
<span className="text-[10px] text-[#A0A0A0] uppercase tracking-widest mt-1">
{item.desc}
</span>
</div>
))}
</div>
<button
onMouseEnter={() => setFocusIndex(contributors.length)}
onClick={() => {
playSfx("close_click.wav");
onClose();
}}
className={`mt-6 w-56 h-12 flex items-center justify-center transition-colors text-2xl mc-text-shadow outline-none border-none ${focusIndex === contributors.length ? "text-[#FFFF55]" : "text-white"}`}
style={{
backgroundImage: focusIndex === contributors.length
? "url('/images/button_highlighted.png')"
: "url('/images/Button_Background.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
Close
</button>
</div>
</motion.div>
);
}

View file

@ -3,7 +3,7 @@ import { motion } from "framer-motion";
import { useUI, useConfig, useAudio, useGame } from "../../context/LauncherContext";
const HomeView = memo(function HomeView() {
const { setActiveView, setShowCredits, setShowSpecialThanks, focusSection, onNavigateToSkin } = useUI();
const { setActiveView, setShowCredits, focusSection, onNavigateToSkin } = useUI();
const { profile, legacyMode } = useConfig();
const { playClickSound, playSfx } = useAudio();
const { handleLaunch, isGameRunning, editions, installs, toggleInstall, downloadProgress, downloadingId } = useGame();
@ -155,17 +155,6 @@ const HomeView = memo(function HomeView() {
>
EMERALD TEAM
</button>
<button
onClick={() => {
if (isFocusedSection) {
playSfx("orb.ogg");
setShowSpecialThanks(true);
}
}}
className={`text-white/60 hover:text-[#FFFF55] text-xs mc-text-shadow tracking-[0.2em] transition-colors bg-transparent border-none outline-none ${!isFocusedSection ? "cursor-default pointer-events-none" : ""}`}
>
SPECIAL THANKS
</button>
</div>
)}
</motion.div>

View file

@ -207,13 +207,13 @@ const SettingsView = memo(function SettingsView() {
if (currentSubMenu === "main") {
items.push({
id: "audio_menu",
label: "Audio",
label: "Audio Settings",
type: "button",
onClick: () => { playClickSound(); setCurrentSubMenu("audio"); setFocusIndex(0); },
});
items.push({
id: "video_menu",
label: "User Interface",
label: "Video Settings",
type: "button",
onClick: () => { playClickSound(); setCurrentSubMenu("video"); setFocusIndex(0); },
});
@ -225,23 +225,23 @@ const SettingsView = memo(function SettingsView() {
});
items.push({
id: "launcher_menu",
label: "Options",
label: "Launcher Settings",
type: "button",
onClick: () => { playClickSound(); setCurrentSubMenu("launcher"); setFocusIndex(0); },
});
} else if (currentSubMenu === "audio") {
items.push({
id: "music",
label: `Music: ${musicVolume ?? 50}%`,
label: `Music: ${musicVolume}%`,
type: "slider",
value: musicVolume ?? 50,
value: musicVolume,
onChange: setMusicVolume,
});
items.push({
id: "sfx",
label: `SFX: ${sfxVolume ?? 100}%`,
label: `SFX: ${sfxVolume}%`,
type: "slider",
value: sfxVolume ?? 100,
value: sfxVolume,
onChange: setSfxVolume,
});
items.push({
@ -480,7 +480,7 @@ const SettingsView = memo(function SettingsView() {
className="flex flex-col items-center w-full max-w-2xl outline-none"
>
<h2 className="text-2xl text-white mc-text-shadow mt-2 mb-4 border-b-2 border-[#373737] pb-2 w-[40%] max-w-[200px] text-center tracking-widest uppercase opacity-80 font-bold whitespace-nowrap px-4">
{currentSubMenu === "main" ? "Settings" : currentSubMenu === "audio" ? "Audio" : currentSubMenu === "video" ? "User Interface" : currentSubMenu === "controls" ? "Controls" : "Options"}
{currentSubMenu === "main" ? "Settings" : currentSubMenu === "audio" ? "Audio Settings" : currentSubMenu === "video" ? "Video Settings" : currentSubMenu === "controls" ? "Controls" : "Launcher"}
</h2>
<div className="w-full max-w-[540px] space-y-2 mb-4 p-6 flex flex-col items-center overflow-y-auto max-h-[55vh]">

View file

@ -8,7 +8,7 @@ const VersionsView = memo(function VersionsView() {
const { setActiveView } = useUI();
const { profile: selectedProfile, setProfile: setSelectedProfile } = useConfig();
const { playClickSound, playBackSound, playSfx } = useAudio();
const { editions, installs: installedVersions, toggleInstall, handleUninstall: onUninstall, deleteCustomEdition: onDeleteEdition, addCustomEdition: onAddEdition, updateCustomEdition: onUpdateEdition, downloadingId } = useGame();
const { editions, installs: installedVersions, toggleInstall, handleUninstall: onUninstall, deleteCustomEdition: onDeleteEdition, addCustomEdition: onAddEdition, updateCustomEdition: onUpdateEdition, downloadingId, downloadProgress } = useGame();
const [focusRow, setFocusRow] = useState<number>(0);
const [focusCol, setFocusCol] = useState<number>(0);
@ -35,49 +35,34 @@ const VersionsView = memo(function VersionsView() {
setFocusCol(0);
} else if (e.key === "ArrowRight") {
if (focusRow < editions.length) {
const edition = editions[focusRow];
const isInstalled = installedVersions.includes(edition.id);
const isCustom = edition.id.startsWith("custom_");
const hasCredits = !isCustom && edition.credits;
const id = editions[focusRow].id;
const isInstalled = installedVersions.includes(id);
const isCustom = id.startsWith("custom_");
let maxCol = 1;
if (isInstalled) maxCol = 3;
if (isCustom) maxCol = isInstalled ? 5 : 3;
if (hasCredits) maxCol = Math.max(maxCol, 0); // credits button is at col -1
setFocusCol((prev) => (prev < maxCol ? prev + 1 : prev));
}
} else if (e.key === "ArrowLeft") {
if (focusRow < editions.length) {
const edition = editions[focusRow];
const isCustom = edition.id.startsWith("custom_");
const hasCredits = !isCustom && edition.credits;
if (hasCredits && focusCol > -1) {
setFocusCol(-1);
} else if (focusCol > 0) {
setFocusCol((prev) => prev - 1);
}
} else {
setFocusCol((prev) => (prev > 0 ? prev - 1 : prev));
}
setFocusCol((prev) => (prev > 0 ? prev - 1 : prev));
} else if (e.key === "Enter") {
if (focusRow < editions.length) {
const edition = editions[focusRow];
const isInstalled = installedVersions.includes(edition.id);
const isCustom = edition.id.startsWith("custom_");
if (focusCol === -1) {
// Credits button
if (edition.credits) {
if (focusCol === 0) {
if (isInstalled) {
playClickSound();
window.open(edition.credits.url, '_blank');
}
} else if (focusCol === 1) {
if (!downloadingId) {
setSelectedProfile(edition.id);
} else if (!downloadingId) {
playClickSound();
toggleInstall(edition.id);
}
} else if (focusCol === 1 && !downloadingId) {
playClickSound();
toggleInstall(edition.id);
} else if (focusCol === 2) {
if (isInstalled) {
playClickSound();
@ -116,10 +101,22 @@ const VersionsView = memo(function VersionsView() {
}
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [editions, focusRow, focusCol, downloadingId, installedVersions, onUninstall, onDeleteEdition, ITEM_COUNT]);
}, [
focusRow,
focusCol,
editions,
installedVersions,
playClickSound,
playBackSound,
setSelectedProfile,
setActiveView,
toggleInstall,
onUninstall,
onDeleteEdition,
ITEM_COUNT,
]);
useEffect(() => {
const el = containerRef.current?.querySelector(
@ -142,381 +139,304 @@ const VersionsView = memo(function VersionsView() {
</h2>
<div className="w-full max-w-[740px] h-[380px] overflow-y-auto mb-6 p-6 relative">
<div
className="w-full p-6"
style={{
backgroundImage: "url('/images/frame_background.png')",
backgroundSize: "100% 100%",
backgroundRepeat: "no-repeat",
imageRendering: "pixelated",
minHeight: "340px",
}}
>
<div className="flex flex-col gap-3">
{editions.map((edition: any, i: number) => {
const isInstalled = installedVersions.includes(edition.id);
const isSelected = selectedProfile === edition.id;
const isRowFocused = focusRow === i;
const isCustom = edition.id.startsWith("custom_");
const isPlaceholder = edition.id === "lmrp_placeholder";
<div className="flex flex-col gap-3">
{editions.map((edition: any, i: number) => {
const isInstalled = installedVersions.includes(edition.id);
const isSelected = selectedProfile === edition.id;
const isRowFocused = focusRow === i;
const isCustom = edition.id.startsWith("custom_");
return (
return (
<div
key={edition.id}
className={`w-full flex items-center transition-all border-none outline-none overflow-hidden`}
style={{
backgroundImage:
isSelected || (isRowFocused && focusCol === 0)
? "url('/images/button_highlighted.png')"
: "url('/images/Button_Background.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
<div
key={edition.id}
className={`w-full p-4 flex items-center transition-all border-none outline-none overflow-hidden relative ${isPlaceholder ? 'bg-gray-800/50 border-2 border-gray-600 opacity-50' : isSelected ? 'bg-[#50C878]/20 border-2 border-[#50C878]' :
isRowFocused ? 'bg-white/5 border-2 border-white/50' :
'bg-black/30 border-2 border-transparent hover:bg-white/5'
}`}
data-row={i}
data-col={0}
tabIndex={0}
onMouseEnter={() => {
if (!isPlaceholder) {
setFocusRow(i);
setFocusCol(0);
}
setFocusRow(i);
setFocusCol(0);
}}
onClick={() => {
if (!isPlaceholder && isInstalled) {
if (isInstalled) {
playClickSound();
setSelectedProfile(edition.id);
} else {
toggleInstall(edition.id);
}
}}
style={{
backdropFilter: 'blur(4px)',
cursor: isPlaceholder ? 'not-allowed' : isInstalled ? 'pointer' : 'default',
imageRendering: 'pixelated',
borderRadius: '0'
}}
className="flex-1 p-4 flex items-center cursor-pointer outline-none pl-6 text-left relative"
>
<div className="flex flex-col flex-1">
<div className="flex items-center gap-3 mb-1">
<div className="flex flex-col">
<div className="flex items-center gap-3">
<span
className={`text-xl mc-text-shadow ${isSelected ? "text-[#50C878]" : "text-white"}`}
style={{ imageRendering: 'pixelated' }}
className={`text-2xl mc-text-shadow ${isSelected || (isRowFocused && focusCol === 0) ? "text-[#FFFF55]" : "text-white"}`}
>
{edition.name}
</span>
{isCustom && (
<span
className="text-[10px] bg-[#50C878] text-black px-1 font-bold uppercase mc-text-shadow-none"
style={{ imageRendering: 'pixelated' }}
>
<span className="text-[10px] bg-[#FFFF55] text-black px-1 font-bold uppercase mc-text-shadow-none">
Custom
</span>
)}
{edition.id === "revelations_edition" && (
<>
<span
className="text-[10px] bg-[#50C878] text-white px-1 font-bold uppercase mc-text-shadow-none"
style={{ imageRendering: 'pixelated' }}
>
New
</span>
<span
className="text-[10px] bg-[#FFD700] text-black px-1 font-bold uppercase mc-text-shadow-none"
style={{ imageRendering: 'pixelated' }}
>
Recommended
</span>
</>
)}
{edition.id === "360revived" && (
<span
className="text-[10px] bg-[#50C878] text-white px-1 font-bold uppercase mc-text-shadow-none"
style={{ imageRendering: 'pixelated' }}
>
New
</span>
)}
{edition.id === "lmrp_placeholder" && (
<span
className="text-[10px] bg-gray-500 text-white px-1 font-bold uppercase mc-text-shadow-none"
style={{ imageRendering: 'pixelated' }}
>
Coming Soon
</span>
)}
{!isCustom && edition.credits && (
<span
className="text-xs text-[#B0B0B0] mc-text-shadow"
style={{ imageRendering: 'pixelated' }}
>
by {edition.credits.developer}
</span>
)}
</div>
<div
className="text-sm text-[#E0E0E0] mc-text-shadow"
style={{ imageRendering: 'pixelated' }}
>
<span className="text-base text-[#E0E0E0] mc-text-shadow truncate w-full">
{edition.desc}
</div>
</span>
</div>
</div>
{!isPlaceholder && (
<div className="flex items-center gap-2">
{!isCustom && edition.credits && (
<button
data-row={i}
data-col={-1}
onMouseEnter={(e) => {
e.stopPropagation();
setFocusRow(i);
setFocusCol(-1);
}}
onClick={(e) => {
e.stopPropagation();
playClickSound();
window.open(edition.credits.url, '_blank');
}}
className={`mc-sq-btn w-8 h-8 flex items-center justify-center outline-none border-none transition-all`}
style={{
backgroundImage:
isRowFocused && focusCol === -1
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
title={`Credits: ${edition.credits.developer} (${edition.credits.platform})`}
>
{edition.credits?.platform === "codeberg" ? (
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="currentColor"
className="text-white drop-shadow-md"
>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z" />
</svg>
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="text-white drop-shadow-md"
>
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
</svg>
)}
</button>
)}
{!isInstalled ? (
<button
data-row={i}
data-col={1}
onMouseEnter={(e) => {
e.stopPropagation();
setFocusRow(i);
setFocusCol(1);
}}
onClick={(e) => {
e.stopPropagation();
if (!downloadingId) {
playClickSound();
toggleInstall(edition.id);
}
}}
className={`mc-sq-btn w-8 h-8 flex items-center justify-center outline-none border-none transition-all ${downloadingId === edition.id ? "opacity-100" : downloadingId ? "opacity-50" : ""}`}
style={{
backgroundImage:
isRowFocused && focusCol === 1
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
{downloadingId === edition.id ? (
<img
src="/images/loading.gif"
alt="Loading"
className="w-6 h-6 object-contain pointer-events-none drop-shadow-md"
style={{ imageRendering: "pixelated" }}
loading="lazy"
decoding="async"
/>
) : (
<img
src="/images/Download_Icon.png"
alt="Download"
className="w-6 h-6 object-contain pointer-events-none drop-shadow-md"
style={{ imageRendering: "pixelated" }}
loading="lazy"
decoding="async"
/>
)}
</button>
<div className="flex items-center gap-3 p-3 pr-6">
{!isInstalled ? (
<button
data-row={i}
data-col={1}
onMouseEnter={() => {
setFocusRow(i);
setFocusCol(1);
}}
onClick={(e) => {
e.stopPropagation();
if (!downloadingId) {
playClickSound();
toggleInstall(edition.id);
}
}}
className={`mc-sq-btn w-10 h-10 flex items-center justify-center outline-none border-none transition-all ${downloadingId === edition.id ? "opacity-100" : downloadingId ? "opacity-50" : ""}`}
style={{
backgroundImage:
isRowFocused && focusCol === 1
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
{downloadingId === edition.id ? (
<div className="flex flex-col items-center justify-center">
<span className="text-[10px] text-white font-bold leading-none">
{Math.floor(downloadProgress || 0)}%
</span>
</div>
) : (
<>
<button
data-row={i}
data-col={2}
onMouseEnter={(e) => {
e.stopPropagation();
setFocusRow(i);
setFocusCol(2);
}}
onClick={(e) => {
e.stopPropagation();
playClickSound();
TauriService.openInstanceFolder(edition.id);
}}
className="mc-sq-btn w-8 h-8 flex items-center justify-center outline-none border-none transition-all"
style={{
backgroundImage:
isRowFocused && focusCol === 2
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
<img
src="/images/Folder_Icon.png"
alt="Folder"
className="w-6 h-6 object-contain pointer-events-none drop-shadow-md"
style={{ imageRendering: "pixelated" }}
loading="lazy"
decoding="async"
/>
</button>
<button
data-row={i}
data-col={3}
onMouseEnter={(e) => {
e.stopPropagation();
setFocusRow(i);
setFocusCol(3);
}}
onClick={(e) => {
e.stopPropagation();
playBackSound();
onUninstall(edition.id);
}}
className="mc-sq-btn w-8 h-8 flex items-center justify-center outline-none border-none transition-all"
style={{
backgroundImage:
isRowFocused && focusCol === 3
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="square"
className="text-white drop-shadow-md"
>
<polyline points="3 6 5 6 21 6"></polyline>
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
<line x1="10" y1="11" x2="10" y2="17"></line>
<line x1="14" y1="11" x2="14" y2="17"></line>
</svg>
</button>
</>
<img
src="/images/Download_Icon.png"
alt="Download"
className="w-8 h-8 object-contain pointer-events-none drop-shadow-md"
style={{ imageRendering: "pixelated" }}
loading="lazy"
decoding="async"
/>
)}
{isCustom && (
<>
<button
data-row={i}
data-col={isInstalled ? 4 : 2}
onMouseEnter={(e) => {
e.stopPropagation();
setFocusRow(i);
setFocusCol(isInstalled ? 4 : 2);
}}
onClick={(e) => {
e.stopPropagation();
playClickSound();
setEditingEdition(edition);
setIsImportModalOpen(true);
}}
className="mc-sq-btn w-8 h-8 flex items-center justify-center outline-none border-none transition-all"
style={{
backgroundImage:
isRowFocused && focusCol === (isInstalled ? 4 : 2)
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="square"
className="text-white drop-shadow-md"
>
<path d="M12 20h9"></path>
<path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"></path>
</svg>
</button>
<button
data-row={i}
data-col={isInstalled ? 5 : 3}
onMouseEnter={(e) => {
e.stopPropagation();
setFocusRow(i);
setFocusCol(isInstalled ? 5 : 3);
}}
onClick={(e) => {
e.stopPropagation();
playBackSound();
onDeleteEdition(edition.id);
}}
className="mc-sq-btn w-8 h-8 flex items-center justify-center outline-none border-none transition-all"
style={{
backgroundImage:
isRowFocused && focusCol === (isInstalled ? 5 : 3)
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="3"
strokeLinecap="square"
className="text-red-500 drop-shadow-md"
>
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</>
)}
</div>
</button>
) : (
<>
<button
data-row={i}
data-col={1}
onMouseEnter={() => {
setFocusRow(i);
setFocusCol(1);
}}
onClick={(e) => {
e.stopPropagation();
if (!downloadingId) {
playClickSound();
toggleInstall(edition.id);
}
}}
className={`mc-sq-btn w-10 h-10 flex items-center justify-center outline-none border-none transition-all ${downloadingId === edition.id ? "opacity-100" : downloadingId ? "opacity-50" : ""}`}
style={{
backgroundImage:
isRowFocused && focusCol === 1
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
{downloadingId === edition.id ? (
<div className="flex flex-col items-center justify-center">
<span className="text-[10px] text-white font-bold leading-none">
{Math.floor(downloadProgress || 0)}%
</span>
</div>
) : (
<img
src="/images/Update_Icon.png"
alt="Update"
className="w-8 h-8 object-contain pointer-events-none drop-shadow-md"
style={{ imageRendering: "pixelated" }}
loading="lazy"
decoding="async"
/>
)}
</button>
<button
data-row={i}
data-col={2}
onMouseEnter={() => {
setFocusRow(i);
setFocusCol(2);
}}
onClick={(e) => {
e.stopPropagation();
playClickSound();
TauriService.openInstanceFolder(edition.id);
}}
className="mc-sq-btn w-10 h-10 flex items-center justify-center outline-none border-none transition-all"
style={{
backgroundImage:
isRowFocused && focusCol === 2
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
<img
src="/images/Folder_Icon.png"
alt="Folder"
className="w-8 h-8 object-contain pointer-events-none drop-shadow-md"
style={{ imageRendering: "pixelated" }}
loading="lazy"
decoding="async"
/>
</button>
<button
data-row={i}
data-col={3}
onMouseEnter={() => {
setFocusRow(i);
setFocusCol(3);
}}
onClick={(e) => {
e.stopPropagation();
playBackSound();
onUninstall(edition.id);
}}
className="mc-sq-btn w-10 h-10 flex items-center justify-center outline-none border-none transition-all"
style={{
backgroundImage:
isRowFocused && focusCol === 3
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="square"
className="text-white drop-shadow-md"
>
<polyline points="3 6 5 6 21 6"></polyline>
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
<line x1="10" y1="11" x2="10" y2="17"></line>
<line x1="14" y1="11" x2="14" y2="17"></line>
</svg>
</button>
</>
)}
{isCustom && (
<>
<button
data-row={i}
data-col={isInstalled ? 4 : 2}
onMouseEnter={() => {
setFocusRow(i);
setFocusCol(isInstalled ? 4 : 2);
}}
onClick={(e) => {
e.stopPropagation();
playClickSound();
setEditingEdition(edition);
setIsImportModalOpen(true);
}}
className="mc-sq-btn w-10 h-10 flex items-center justify-center outline-none border-none transition-all"
style={{
backgroundImage:
isRowFocused && focusCol === (isInstalled ? 4 : 2)
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="square"
className="text-white drop-shadow-md"
>
<path d="M12 20h9"></path>
<path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"></path>
</svg>
</button>
<button
data-row={i}
data-col={isInstalled ? 5 : 3}
onMouseEnter={() => {
setFocusRow(i);
setFocusCol(isInstalled ? 5 : 3);
}}
onClick={(e) => {
e.stopPropagation();
playBackSound();
onDeleteEdition(edition.id);
}}
className="mc-sq-btn w-10 h-10 flex items-center justify-center outline-none border-none transition-all"
style={{
backgroundImage:
isRowFocused && focusCol === (isInstalled ? 5 : 3)
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="3"
strokeLinecap="square"
className="text-red-500 drop-shadow-md"
>
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</>
)}
</div>
);
})}
</div>
</div>
);
})}
</div>
</div>
@ -532,7 +452,7 @@ const VersionsView = memo(function VersionsView() {
playClickSound();
setIsImportModalOpen(true);
}}
className={`w-72 h-14 flex items-center justify-center transition-colors text-2xl mc-text-shadow outline-none border-none ${focusRow === editions.length ? "text-[#50C878]" : "text-white"}`}
className={`w-72 h-14 flex items-center justify-center transition-colors text-2xl mc-text-shadow outline-none border-none ${focusRow === editions.length ? "text-[#FFFF55]" : "text-white"}`}
style={{
backgroundImage:
focusRow === editions.length
@ -556,7 +476,7 @@ const VersionsView = memo(function VersionsView() {
playBackSound();
setActiveView("main");
}}
className={`w-72 h-14 flex items-center justify-center transition-colors text-2xl mc-text-shadow outline-none border-none ${focusRow === editions.length + 1 ? "text-[#50C878]" : "text-white"}`}
className={`w-72 h-14 flex items-center justify-center transition-colors text-2xl mc-text-shadow outline-none border-none ${focusRow === editions.length + 1 ? "text-[#FFFF55]" : "text-white"}`}
style={{
backgroundImage:
focusRow === editions.length + 1

View file

@ -20,8 +20,6 @@ interface UIContextType {
isWindowVisible: boolean;
showCredits: boolean;
setShowCredits: (show: boolean) => void;
showSpecialThanks: boolean;
setShowSpecialThanks: (show: boolean) => void;
focusSection: "menu" | "skin";
setFocusSection: (section: "menu" | "skin") => void;
onNavigateToSkin: () => void;
@ -44,7 +42,6 @@ export function LauncherProvider({ children }: { children: React.ReactNode }) {
const [isUiHidden, setIsUiHidden] = useState(false);
const [isWindowVisible, setIsWindowVisible] = useState(true);
const [showCredits, setShowCredits] = useState(false);
const [showSpecialThanks, setShowSpecialThanks] = useState(false);
const [focusSection, setFocusSection] = useState<"menu" | "skin">("menu");
const { updateMessage, clearUpdateMessage } = useUpdateCheck();
@ -71,19 +68,13 @@ export function LauncherProvider({ children }: { children: React.ReactNode }) {
configRaw.rpcEnabled, configRaw.musicVol, configRaw.sfxVol, configRaw.isDayTime,
configRaw.profile, configRaw.linuxRunner, configRaw.perfBoost, configRaw.customEditions,
configRaw.legacyMode, configRaw.keepLauncherOpen, configRaw.enableTrayIcon,
configRaw.animationsEnabled, configRaw.saveConfig, configRaw.setUsername, configRaw.setTheme,
configRaw.setLayout, configRaw.setVfxEnabled, configRaw.setAnimationsEnabled,
configRaw.setRpcEnabled, configRaw.setMusicVol, configRaw.setSfxVol, configRaw.setIsDayTime,
configRaw.setProfile, configRaw.setLinuxRunner, configRaw.setPerfBoost, configRaw.setCustomEditions,
configRaw.isLoaded, configRaw.hasCompletedSetup, configRaw.setHasCompletedSetup
configRaw.animationsEnabled
]);
const game = useMemo(() => gameRaw, [
gameRaw.installs, gameRaw.isGameRunning, gameRaw.downloadProgress,
gameRaw.downloadingId, gameRaw.editions, gameRaw.isRunnerDownloading,
gameRaw.runnerDownloadProgress, gameRaw.error, gameRaw.updateCustomEdition, configRaw.profile,
gameRaw.handleLaunch, gameRaw.stopGame, gameRaw.toggleInstall, gameRaw.handleUninstall,
gameRaw.addCustomEdition, gameRaw.deleteCustomEdition, gameRaw.downloadRunner, gameRaw.checkInstalls
gameRaw.runnerDownloadProgress, gameRaw.error, gameRaw.updateCustomEdition, configRaw.profile
]);
const audio = useMemo(() => audioRaw, [
@ -174,10 +165,10 @@ export function LauncherProvider({ children }: { children: React.ReactNode }) {
activeView, setActiveView, showIntro, setShowIntro,
logoAnimDone, setLogoAnimDone, isUiHidden, setIsUiHidden,
isWindowVisible,
showCredits, setShowCredits, showSpecialThanks, setShowSpecialThanks, focusSection, setFocusSection,
showCredits, setShowCredits, focusSection, setFocusSection,
onNavigateToSkin, onNavigateToMenu, connected,
updateMessage, clearUpdateMessage
}), [activeView, showIntro, logoAnimDone, isUiHidden, isWindowVisible, showCredits, showSpecialThanks, focusSection, onNavigateToSkin, onNavigateToMenu, connected, updateMessage, clearUpdateMessage]);
}), [activeView, showIntro, logoAnimDone, isUiHidden, isWindowVisible, showCredits, focusSection, onNavigateToSkin, onNavigateToMenu, connected, updateMessage, clearUpdateMessage]);
return (
<UIContext.Provider value={uiValue}>

View file

@ -21,7 +21,7 @@
border: 4px solid transparent;
border-image: url('/images/Button_Background.png') 4 stretch;
image-rendering: pixelated;
background: rgba(0, 0, 0, 0.6);
background: rgba(0,0,0,0.6);
transition: all 0.2s ease;
}
@ -102,13 +102,4 @@ body {
.no-animations * {
transition: none !important;
animation: none !important;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}

View file

@ -37,8 +37,8 @@ export function useAppConfig() {
if (config.vfxEnabled !== undefined) setVfxEnabled(config.vfxEnabled);
if (config.animationsEnabled !== undefined) setAnimationsEnabled(config.animationsEnabled);
if (config.rpcEnabled !== undefined) setRpcEnabled(config.rpcEnabled);
if (config.musicVol !== undefined && config.musicVol !== null) setMusicVol(config.musicVol);
if (config.sfxVol !== undefined && config.sfxVol !== null) setSfxVol(config.sfxVol);
if (config.musicVol !== undefined) setMusicVol(config.musicVol);
if (config.sfxVol !== undefined) setSfxVol(config.sfxVol);
if (config.legacyMode !== undefined) setLegacyMode(config.legacyMode);
setIsLoaded(true);
});
@ -83,9 +83,9 @@ export function useAppConfig() {
setAnimationsEnabled,
rpcEnabled,
setRpcEnabled,
musicVol: musicVol ?? 50,
musicVol,
setMusicVol,
sfxVol: sfxVol ?? 100,
sfxVol,
setSfxVol,
isDayTime,
setIsDayTime,

View file

@ -5,65 +5,26 @@ import { TauriService } from "../services/TauriService";
const appWindow = getCurrentWindow();
const BASE_EDITIONS = [
{
id: "revelations_edition",
name: "Revelations",
desc: "Enhanced LCE with uncapped FPS, graphics fixes, hardcore hearts, and dedicated server security. Features LAN multiplayer, split-screen, and keyboard & mouse support.",
url: "https://github.com/itsRevela/MinecraftConsoles/releases/download/Nightly/LCREWindows64.zip",
titleImage: "/images/minecraft_title_revelations.png",
credits: {
developer: "itsRevela",
platform: "github",
url: "https://github.com/itsRevela"
}
},
{
id: "360revived",
name: "360 Revived",
desc: "PC port of Xbox 360 Edition TU19 with desktop optimizations. Features keyboard & mouse, fullscreen, LAN multiplayer, dedicated server, and split-screen support.",
url: "https://github.com/BluTac10/360Revived/releases/download/nightly/LCEWindows64.zip",
titleImage: "/images/minecraft_title_360revived.png",
credits: {
developer: "BluTac10",
platform: "github",
url: "https://github.com/BluTac10"
}
},
{
id: "legacy_evolved",
name: "Legacy Evolved",
desc: "Backports newer title updates to LCE TU19 base. Currently porting TU25 (98% complete) and TU31 (76% complete).",
desc: "Backporting the newer title updates back to the LCE",
url: "https://codeberg.org/piebot/LegacyEvolved/releases/download/nightly/LCEWindows64.zip",
titleImage: "/images/minecraft_title_LegacyEvolved.png",
credits: {
developer: "piebot",
platform: "codeberg",
url: "https://codeberg.org/piebot"
}
},
{
id: "vanilla_tu19",
name: "Title Update 19",
desc: "Minecraft LCE v1.6.0560.0 with compilation fixes. Base version for modding with keyboard & mouse, fullscreen, LAN multiplayer, and dedicated server support.",
desc: "Leaked 4J Studios build. (smartcmd)",
url: "https://github.com/smartcmd/MinecraftConsoles/releases/download/nightly/LCEWindows64.zip",
titleImage: "/images/minecraft_title_tu19.png",
credits: {
developer: "smartcmd",
platform: "github",
url: "https://github.com/smartcmd"
}
},
{
id: "lmrp_placeholder",
name: "LMRP (Coming Soon)",
desc: "Legacy Minecraft Restoration Project - Classic mini-games and nostalgic gameplay. Stay tuned for updates!",
url: "",
titleImage: "/images/minecraft_title_lmrp.png",
credits: {
developer: "LMRP Team",
platform: "github",
url: "https://github.com/LMRP-Project"
}
id: "360revived",
name: "360 Revived",
desc: "PC port of Xbox 360 Edition TU19",
url: "https://github.com/BluTac10/360Revived/releases/download/nightly/LCEWindows64.zip",
titleImage: "/images/minecraft_title_360revived.png",
},
];
@ -175,7 +136,7 @@ export function useGameManager({ profile, setProfile, customEditions, setCustomE
await appWindow.unminimize();
await appWindow.setFocus();
}
}, [isGameRunning, profile, keepLauncherOpen]);
}, [isGameRunning, profile]);
const stopGame = useCallback(async () => {
try {

View file

@ -9,7 +9,6 @@ import WorkshopView from "../components/views/WorkshopView";
import SetupView from "../components/views/SetupView";
import SkinViewer from "../components/common/SkinViewer";
import TeamModal from "../components/modals/TeamModal";
import SpecialThanksModal from "../components/modals/SpecialThanksModal";
import PanoramaBackground from "../components/common/PanoramaBackground";
import { ClickParticles } from "../components/common/ClickParticles";
import { AppHeader } from "../components/layout/AppHeader";
@ -25,7 +24,7 @@ export default function App() {
const {
showIntro, setShowIntro, logoAnimDone, setLogoAnimDone,
activeView, setActiveView, isUiHidden, setIsUiHidden,
showCredits, setShowCredits, showSpecialThanks, setShowSpecialThanks, focusSection,
showCredits, setShowCredits, focusSection,
onNavigateToMenu, updateMessage, clearUpdateMessage
} = useUI();
@ -126,14 +125,6 @@ export default function App() {
playSfx={audio.playSfx}
/>
)}
{showSpecialThanks && (
<SpecialThanksModal
isOpen={showSpecialThanks}
onClose={() => setShowSpecialThanks(false)}
playClickSound={audio.playClickSound}
playSfx={audio.playSfx}
/>
)}
</AnimatePresence>
<AnimatePresence>