mirror of
https://github.com/LCE-Hub/LCE-Emerald-Launcher.git
synced 2026-07-18 00:07:09 +00:00
merge experimental into main (#42)
This commit is contained in:
parent
e29fd4da6f
commit
46e04a7c4b
16
.github/workflows/experimental.yml
vendored
16
.github/workflows/experimental.yml
vendored
|
|
@ -55,7 +55,7 @@ jobs:
|
|||
run: pnpm install
|
||||
|
||||
- name: build Tauri app
|
||||
run: pnpm tauri build -- ${{ matrix.args }}
|
||||
run: pnpm run tauri:build -- ${{ matrix.args }}
|
||||
env:
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
|
|
@ -65,23 +65,27 @@ jobs:
|
|||
run: |
|
||||
mkdir -p pkg_temp/scripts
|
||||
cp scripts/postinstall.sh pkg_temp/scripts/
|
||||
APP_PATH=$(find src-tauri/target/release/bundle/macos/ -name "*.app" | head -1)
|
||||
MACOS_BUNDLE_DIR=$(find src-tauri/target -path "*/release/bundle/macos" -type d | head -n 1)
|
||||
APP_PATH=$(find "$MACOS_BUNDLE_DIR" -name "*.app" -type d | head -n 1)
|
||||
if [ -z "$APP_PATH" ]; then
|
||||
echo "No .app found in $MACOS_BUNDLE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
APP_NAME=$(basename "$APP_PATH")
|
||||
pkgbuild --root "$APP_PATH/.." \
|
||||
--install-location /Applications \
|
||||
--scripts pkg_temp/scripts \
|
||||
--identifier "com.emerald.legacy" \
|
||||
--version "1.0.0" \
|
||||
--install-location "/Applications" \
|
||||
--root "$APP_PATH" \
|
||||
"Emerald-Legacy-Launcher.pkg"
|
||||
mv "Emerald-Legacy-Launcher.pkg" src-tauri/target/release/bundle/macos/
|
||||
mv "Emerald-Legacy-Launcher.pkg" "$MACOS_BUNDLE_DIR/"
|
||||
|
||||
- name: upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact-name }}
|
||||
path: src-tauri/target/release/bundle/
|
||||
path: |
|
||||
src-tauri/target/*/release/bundle/**/*
|
||||
|
||||
build-flatpak:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
59
.github/workflows/nightly.yml
vendored
59
.github/workflows/nightly.yml
vendored
|
|
@ -14,12 +14,16 @@ jobs:
|
|||
include:
|
||||
- platform: 'macos-latest'
|
||||
args: '--target aarch64-apple-darwin'
|
||||
artifact-name: macos-aarch64
|
||||
- platform: 'macos-latest'
|
||||
args: '--target x86_64-apple-darwin'
|
||||
artifact-name: macos-x86_64
|
||||
- platform: 'ubuntu-22.04'
|
||||
args: ''
|
||||
artifact-name: linux
|
||||
- platform: 'windows-latest'
|
||||
args: ''
|
||||
artifact-name: windows
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
|
|
@ -53,18 +57,34 @@ jobs:
|
|||
|
||||
- name: install frontend dependencies
|
||||
run: pnpm install
|
||||
- name: build and fix macOS
|
||||
if: matrix.platform == 'macos-latest'
|
||||
run: |
|
||||
pnpm tauri build ${{ matrix.args }}
|
||||
pnpm run post-build:macos
|
||||
- uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: build Tauri app
|
||||
run: pnpm run tauri:build -- ${{ matrix.args }}
|
||||
|
||||
- name: upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
tagName: nightly
|
||||
releaseName: 'Emerald Nightly'
|
||||
releaseBody: |
|
||||
name: ${{ matrix.artifact-name }}
|
||||
path: |
|
||||
src-tauri/target/*/release/bundle/**/*
|
||||
|
||||
nightly-release:
|
||||
needs: [nightly-tauri, nightly-flatpak]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: '*'
|
||||
merge-multiple: true
|
||||
path: artifacts
|
||||
|
||||
- uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: nightly
|
||||
name: 'Emerald Nightly'
|
||||
body: |
|
||||
# Emerald Legacy Launcher (Nightly)
|
||||
# What to download?
|
||||
- `Emerald.Legacy.Launcher-*.rpm` for GNU/Linux (RHEL)
|
||||
|
|
@ -77,16 +97,17 @@ jobs:
|
|||
---
|
||||
# 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 "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
|
||||
files: artifacts/*
|
||||
fail_on_unmatched_files: false
|
||||
prerelease: true
|
||||
args: ${{ matrix.args }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
nightly-flatpak:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -104,9 +125,7 @@ jobs:
|
|||
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 }}
|
||||
- uses: softprops/action-gh-release@v2
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
files: io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.flatpak
|
||||
tag_name: nightly
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
name: flatpak
|
||||
path: io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.flatpak
|
||||
|
|
|
|||
134
.github/workflows/publish.yml
vendored
134
.github/workflows/publish.yml
vendored
|
|
@ -1,4 +1,4 @@
|
|||
name: 'publish'
|
||||
name: "publish"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
|
@ -20,14 +20,14 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- platform: 'macos-latest'
|
||||
args: '--target aarch64-apple-darwin'
|
||||
- platform: 'macos-latest'
|
||||
args: '--target x86_64-apple-darwin'
|
||||
- platform: 'ubuntu-22.04'
|
||||
args: ''
|
||||
- platform: 'windows-latest'
|
||||
args: ''
|
||||
- platform: "macos-latest"
|
||||
args: "--target aarch64-apple-darwin"
|
||||
- platform: "macos-latest"
|
||||
args: "--target x86_64-apple-darwin"
|
||||
- platform: "ubuntu-22.04"
|
||||
args: ""
|
||||
- platform: "windows-latest"
|
||||
args: ""
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
|
|
@ -47,7 +47,7 @@ jobs:
|
|||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: 'pnpm'
|
||||
cache: "pnpm"
|
||||
|
||||
- name: install Rust stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
|
@ -57,69 +57,43 @@ jobs:
|
|||
- name: Rust cache
|
||||
uses: swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: './src-tauri -> target'
|
||||
workspaces: "./src-tauri -> target"
|
||||
|
||||
- name: install frontend dependencies
|
||||
run: pnpm install
|
||||
- name: Create PKG with post-install script
|
||||
|
||||
- name: build Tauri app
|
||||
run: pnpm run tauri:build -- ${{ matrix.args }}
|
||||
env:
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
|
||||
- name: Create PKG with post-install script (macOS only)
|
||||
if: matrix.platform == 'macos-latest'
|
||||
run: |
|
||||
# Create temporary directory for PKG creation
|
||||
mkdir -p pkg_temp/scripts
|
||||
cp scripts/postinstall.sh pkg_temp/scripts/
|
||||
|
||||
# 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)
|
||||
MACOS_BUNDLE_DIR=$(find src-tauri/target -path "*/release/bundle/macos" -type d | head -n 1)
|
||||
APP_PATH=$(find "$MACOS_BUNDLE_DIR" -name "*.app" -type d | head -n 1)
|
||||
if [ -z "$APP_PATH" ]; then
|
||||
echo "No .app found in $MACOS_BUNDLE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
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 "1.0.0" \
|
||||
--install-location "/Applications" \
|
||||
--root "$APP_PATH" \
|
||||
"Emerald-Legacy-Launcher.pkg"
|
||||
|
||||
# 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 }}
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
with:
|
||||
uploadPlainBinary: true
|
||||
tagName: v__VERSION__
|
||||
releaseName: 'Emerald v__VERSION__'
|
||||
releaseBody: |
|
||||
# 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, Currently Broken)
|
||||
- `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)
|
||||
- `Emerald.Legacy.Launcher.flatpak` for GNU/Linux (Flatpak, Recommended)
|
||||
---
|
||||
# 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 "Damaged" Error Fix
|
||||
The macOS builds now include automatic fixes for Gatekeeper quarantine issues. The app should launch without "application is damaged" errors.
|
||||
mv "Emerald-Legacy-Launcher.pkg" "$MACOS_BUNDLE_DIR/"
|
||||
|
||||
releaseDraft: false
|
||||
prerelease: false
|
||||
args: ${{ matrix.args }}
|
||||
- name: upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.platform }}
|
||||
path: |
|
||||
src-tauri/target/*/release/bundle/**/*
|
||||
|
||||
publish-flatpak:
|
||||
needs: get-version
|
||||
|
|
@ -140,9 +114,49 @@ jobs:
|
|||
bundle: Emerald.Legacy.Launcher.flatpak
|
||||
manifest-path: flatpak/io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher.yml
|
||||
cache-key: flatpak-builder-${{ github.sha }}
|
||||
- name: upload flatpak artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: flatpak
|
||||
path: Emerald.Legacy.Launcher.flatpak
|
||||
|
||||
publish-release:
|
||||
needs: [get-version, publish-tauri, publish-flatpak]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: "*"
|
||||
merge-multiple: true
|
||||
path: artifacts
|
||||
|
||||
- uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: v${{ needs.get-version.outputs.version }}
|
||||
files: Emerald.Legacy.Launcher.flatpak
|
||||
name: "Emerald v${{ needs.get-version.outputs.version }}"
|
||||
body: |
|
||||
# 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, Currently Broken)
|
||||
- `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)
|
||||
- `Emerald.Legacy.Launcher.flatpak` for GNU/Linux (Flatpak, Recommended)
|
||||
---
|
||||
# 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 "Damaged" Error Fix
|
||||
The macOS builds now include automatic fixes for Gatekeeper quarantine issues. The app should launch without "application is damaged" errors.
|
||||
files: artifacts/*
|
||||
draft: true
|
||||
prerelease: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ sdk-extensions:
|
|||
command: emerald-legacy-launcher
|
||||
finish-args:
|
||||
- --share=network
|
||||
- --share=ipc
|
||||
- --share=ipc
|
||||
- --device=input
|
||||
- --socket=x11
|
||||
- --socket=wayland
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@
|
|||
|
||||
set -e
|
||||
|
||||
if [[ "$(uname)" != "Darwin" ]]; then
|
||||
echo "Not macOS, skipping post-build fixes"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
APP_NAME="Emerald Legacy Launcher"
|
||||
BUNDLE_ID="com.emerald.legacy"
|
||||
BASE_DIR="src-tauri/target"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::net::UdpSocket;
|
||||
|
|
@ -100,7 +101,7 @@ pub struct DownloadState { pub token: Arc<Mutex<Option<CancellationToken>>> }
|
|||
pub struct GameState { pub child: Arc<Mutex<Option<tokio::process::Child>>> }
|
||||
|
||||
pub struct ProxyGuard {
|
||||
pub cancel_token: Arc<Mutex<Option<CancellationToken>>>,
|
||||
pub cancel_tokens: Arc<Mutex<HashMap<String, CancellationToken>>>,
|
||||
pub local_port: Arc<Mutex<Option<u16>>>,
|
||||
}
|
||||
|
||||
|
|
@ -1774,10 +1775,19 @@ async fn add_to_steam(
|
|||
title_base64: String,
|
||||
panorama_base64: String,
|
||||
) -> Result<(), String> {
|
||||
let exe_path = std::env::current_exe().map_err(|e| e.to_string())?;
|
||||
let exe_str = exe_path.to_string_lossy().to_string();
|
||||
let launch_options = format!("\"{}\"", instance_id);
|
||||
let start_dir = exe_path.parent().map(|p| p.to_string_lossy().to_string()).unwrap_or_default();
|
||||
let in_flatpak = std::path::Path::new("/.flatpak-info").exists();
|
||||
let (exe_str, launch_options, start_dir) = if in_flatpak {
|
||||
(
|
||||
"/usr/bin/flatpak".to_string(),
|
||||
format!("run io.github.Emerald_Legacy_Launcher.Emerald_Legacy_Launcher \"{}\"", instance_id),
|
||||
std::env::var("HOME").unwrap_or_default(),
|
||||
)
|
||||
} else {
|
||||
let exe_path = std::env::current_exe().map_err(|e| e.to_string())?;
|
||||
let s = exe_path.to_string_lossy().to_string();
|
||||
let dir = exe_path.parent().map(|p| p.to_string_lossy().to_string()).unwrap_or_default();
|
||||
(s, format!("\"{}\"", instance_id), dir)
|
||||
};
|
||||
let app_id_32 = steam_shortcuts_util::app_id_generator::calculate_app_id(&exe_str, &name);
|
||||
//let app_id_64 = ((app_id_32 as u64) << 32) | 0x02000000; //neo: just in case we'll need later.
|
||||
let mut userdata_dirs: Vec<PathBuf> = Vec::new();
|
||||
|
|
@ -2353,15 +2363,19 @@ async fn start_direct_proxy(
|
|||
target_port: u16,
|
||||
) -> Result<u16, String> {
|
||||
let cancel = CancellationToken::new();
|
||||
let session_id = "__direct__".to_string();
|
||||
{
|
||||
let mut token = proxy_state.cancel_token.lock().await;
|
||||
if let Some(old) = token.take() {
|
||||
old.cancel();
|
||||
}
|
||||
*token = Some(cancel.clone());
|
||||
let mut tokens = proxy_state.cancel_tokens.lock().await;
|
||||
tokens.insert(session_id.clone(), cancel.clone());
|
||||
}
|
||||
|
||||
let local_port = run_direct_proxy(&proxy_state, &target_ip, target_port, cancel).await?;
|
||||
|
||||
{
|
||||
let mut tokens = proxy_state.cancel_tokens.lock().await;
|
||||
tokens.remove(&session_id);
|
||||
}
|
||||
|
||||
Ok(local_port)
|
||||
}
|
||||
|
||||
|
|
@ -2377,14 +2391,17 @@ async fn start_relay_proxy(
|
|||
|
||||
let cancel = CancellationToken::new();
|
||||
{
|
||||
let mut token = proxy_state.cancel_token.lock().await;
|
||||
if let Some(old) = token.take() {
|
||||
old.cancel();
|
||||
}
|
||||
*token = Some(cancel.clone());
|
||||
let mut tokens = proxy_state.cancel_tokens.lock().await;
|
||||
tokens.insert(session_id.clone(), cancel.clone());
|
||||
}
|
||||
|
||||
let local_port = run_relay_proxy(&proxy_state, &ws_url, &access_token, cancel).await?;
|
||||
|
||||
{
|
||||
let mut tokens = proxy_state.cancel_tokens.lock().await;
|
||||
tokens.remove(&session_id);
|
||||
}
|
||||
|
||||
Ok(local_port)
|
||||
}
|
||||
|
||||
|
|
@ -2401,21 +2418,36 @@ async fn start_host_relay(
|
|||
|
||||
let cancel = CancellationToken::new();
|
||||
{
|
||||
let mut token = proxy_state.cancel_token.lock().await;
|
||||
if let Some(old) = token.take() {
|
||||
old.cancel();
|
||||
}
|
||||
*token = Some(cancel.clone());
|
||||
let mut tokens = proxy_state.cancel_tokens.lock().await;
|
||||
tokens.insert(session_id.clone(), cancel.clone());
|
||||
}
|
||||
|
||||
run_host_relay(&proxy_state, &ws_url, &access_token, game_port, cancel).await
|
||||
let result = run_host_relay(&proxy_state, &ws_url, &access_token, game_port, cancel).await;
|
||||
|
||||
{
|
||||
let mut tokens = proxy_state.cancel_tokens.lock().await;
|
||||
tokens.remove(&session_id);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn stop_proxy(proxy_state: State<'_, ProxyGuard>) -> Result<(), String> {
|
||||
let mut token = proxy_state.cancel_token.lock().await;
|
||||
if let Some(t) = token.take() {
|
||||
t.cancel();
|
||||
async fn stop_proxy(proxy_state: State<'_, ProxyGuard>, session_id: String) -> Result<(), String> {
|
||||
let mut tokens = proxy_state.cancel_tokens.lock().await;
|
||||
if let Some(token) = tokens.remove(&session_id) {
|
||||
token.cancel();
|
||||
}
|
||||
let mut port = proxy_state.local_port.lock().await;
|
||||
*port = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn stop_all_proxies(proxy_state: State<'_, ProxyGuard>) -> Result<(), String> {
|
||||
let mut tokens = proxy_state.cancel_tokens.lock().await;
|
||||
for (_, token) in tokens.drain() {
|
||||
token.cancel();
|
||||
}
|
||||
let mut port = proxy_state.local_port.lock().await;
|
||||
*port = None;
|
||||
|
|
@ -2455,11 +2487,11 @@ pub fn run() {
|
|||
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||
.manage(DownloadState { token: Arc::new(Mutex::new(None)) })
|
||||
.manage(GameState { child: Arc::new(Mutex::new(None)) })
|
||||
.manage(ProxyGuard { cancel_token: Arc::new(Mutex::new(None)), local_port: Arc::new(Mutex::new(None)) })
|
||||
.manage(ProxyGuard { cancel_tokens: Arc::new(Mutex::new(HashMap::new())), local_port: Arc::new(Mutex::new(None)) })
|
||||
.plugin(tauri_plugin_gamepad::init())
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_drpc::init())
|
||||
.invoke_handler(tauri::generate_handler![setup_macos_runtime, launch_game, stop_game, check_game_installed, save_config, load_config, download_and_install, open_instance_folder, cancel_download, get_available_runners, get_external_palettes, import_theme, pick_folder, download_runner, delete_instance, sync_dlc, fetch_skin, workshop_install, workshop_uninstall, workshop_list_installed, get_screenshots, delete_screenshot, open_screenshot_folder, save_global_skin_pck, check_game_update, check_macos_runtime_installed, check_macos_runtime_installed_fast, download_logo, pick_file, save_file_dialog, write_binary_file, read_binary_file, read_screenshot_as_data_url, add_to_steam, http_proxy_request, get_instance_path, stun_discover, start_direct_proxy, start_relay_proxy, start_host_relay, stop_proxy, join_game])
|
||||
.invoke_handler(tauri::generate_handler![setup_macos_runtime, launch_game, stop_game, check_game_installed, save_config, load_config, download_and_install, open_instance_folder, cancel_download, get_available_runners, get_external_palettes, import_theme, pick_folder, download_runner, delete_instance, sync_dlc, fetch_skin, workshop_install, workshop_uninstall, workshop_list_installed, get_screenshots, delete_screenshot, open_screenshot_folder, save_global_skin_pck, check_game_update, check_macos_runtime_installed, check_macos_runtime_installed_fast, download_logo, pick_file, save_file_dialog, write_binary_file, read_binary_file, read_screenshot_as_data_url, add_to_steam, http_proxy_request, get_instance_path, stun_discover, start_direct_proxy, start_relay_proxy, start_host_relay, stop_proxy, stop_all_proxies, join_game])
|
||||
.setup(|app| {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
if args.len() > 1 && !args[1].starts_with('-') {
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@
|
|||
"entitlements": null,
|
||||
"exceptionDomain": "",
|
||||
"frameworks": [],
|
||||
"signingIdentity": null,
|
||||
"providerShortName": "Emerald"
|
||||
"minimumSystemVersion": "10.15",
|
||||
"signingIdentity": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ export default function ChooseInstanceModal({
|
|||
]);
|
||||
} else {
|
||||
setStatus("Launching game...");
|
||||
await TauriService.stopProxy();
|
||||
await TauriService.stopAllProxies();
|
||||
await TauriService.launchGame(selectedInstance, [
|
||||
{ name: invite.hostName || "LCELive Game", ip: hostIp, port: hostPort }
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@ const LceLiveView = memo(function LceLiveView() {
|
|||
const [isDiscovering, setIsDiscovering] = useState(false);
|
||||
const [invitedFriends, setInvitedFriends] = useState<Set<string>>(new Set());
|
||||
const [showHostMethodPicker, setShowHostMethodPicker] = useState(false);
|
||||
const [hostSessionId, setHostSessionId] = useState<string>("");
|
||||
const [relayStarted, setRelayStarted] = useState(false);
|
||||
const [isAddingFriend, setIsAddingFriend] = useState(false);
|
||||
const [addFriendUsername, setAddFriendUsername] = useState("");
|
||||
const addFriendInputRef = useRef<HTMLInputElement>(null);
|
||||
|
|
@ -160,7 +158,6 @@ const LceLiveView = memo(function LceLiveView() {
|
|||
|
||||
const handleStartHosting = () => {
|
||||
playPressSound();
|
||||
setRelayStarted(false);
|
||||
setShowHostMethodPicker(true);
|
||||
setFocusIndex(0);
|
||||
};
|
||||
|
|
@ -177,7 +174,6 @@ const LceLiveView = memo(function LceLiveView() {
|
|||
setIsHosting(true);
|
||||
setHostStatus(`Hosting at ${endpoint.ip}:25565`);
|
||||
setInvitedFriends(new Set());
|
||||
setHostSessionId("");
|
||||
} catch (e: any) {
|
||||
const msg = typeof e === "string" ? e : e?.message || "Unknown error";
|
||||
setErrorModal("STUN discovery failed: " + msg);
|
||||
|
|
@ -192,8 +188,6 @@ const LceLiveView = memo(function LceLiveView() {
|
|||
setFocusIndex(0);
|
||||
setIsDiscovering(true);
|
||||
setHostStatus("Discovering external IP for invite...");
|
||||
const sessionId = crypto.randomUUID();
|
||||
setHostSessionId(sessionId);
|
||||
try {
|
||||
const endpoint = await TauriService.stunDiscover();
|
||||
setHostIp(endpoint.ip);
|
||||
|
|
@ -202,7 +196,6 @@ const LceLiveView = memo(function LceLiveView() {
|
|||
setHostIp("127.0.0.1");
|
||||
setHostPort(25565);
|
||||
}
|
||||
setRelayStarted(false);
|
||||
setIsHosting(true);
|
||||
setHostStatus("Relay ready - invite friends to activate");
|
||||
setInvitedFriends(new Set());
|
||||
|
|
@ -212,7 +205,7 @@ const LceLiveView = memo(function LceLiveView() {
|
|||
const handleStopHosting = async () => {
|
||||
playPressSound();
|
||||
try {
|
||||
await TauriService.stopProxy();
|
||||
await TauriService.stopAllProxies();
|
||||
await lceLiveService.deactivateGameInvites();
|
||||
} catch (e: any) {
|
||||
console.warn("Stop hosting failed", e);
|
||||
|
|
@ -221,38 +214,37 @@ const LceLiveView = memo(function LceLiveView() {
|
|||
setHostStatus("");
|
||||
setHostIp("");
|
||||
setInvitedFriends(new Set());
|
||||
setHostSessionId("");
|
||||
setRelayStarted(false);
|
||||
};
|
||||
|
||||
const handleInviteFriend = async (friend: LceLiveAccount) => {
|
||||
playPressSound();
|
||||
const name = lceLiveService.displayUsername;
|
||||
const sessionId = crypto.randomUUID();
|
||||
try {
|
||||
await lceLiveService.sendGameInvite(
|
||||
friend.accountId,
|
||||
hostIp,
|
||||
hostPort,
|
||||
name,
|
||||
hostSessionId || undefined,
|
||||
sessionId,
|
||||
);
|
||||
setInvitedFriends((prev) => new Set(prev).add(friend.accountId));
|
||||
if (hostSessionId && !relayStarted) {
|
||||
setRelayStarted(true);
|
||||
setHostStatus("Connecting relay...");
|
||||
const baseUrl = lceLiveService.apiBaseUrl;
|
||||
const accessToken = lceLiveService.accessToken ?? "";
|
||||
TauriService.startHostRelay(baseUrl, accessToken, hostSessionId, 25565)
|
||||
.then(() => setHostStatus("Relay active"))
|
||||
.catch((relayErr: any) => {
|
||||
const relayMsg =
|
||||
typeof relayErr === "string"
|
||||
? relayErr
|
||||
: relayErr?.message || "Unknown error";
|
||||
console.warn("Relay failed:", relayMsg);
|
||||
setHostStatus("Relay disconnected");
|
||||
});
|
||||
}
|
||||
setHostStatus("Connecting relay...");
|
||||
TauriService.startHostRelay(
|
||||
lceLiveService.apiBaseUrl,
|
||||
lceLiveService.accessToken ?? "",
|
||||
sessionId,
|
||||
25565,
|
||||
)
|
||||
.then(() => setHostStatus("Relay active"))
|
||||
.catch((relayErr: any) => {
|
||||
const relayMsg =
|
||||
typeof relayErr === "string"
|
||||
? relayErr
|
||||
: relayErr?.message || "Unknown error";
|
||||
console.warn("Relay failed:", relayMsg);
|
||||
setHostStatus("Relay disconnected");
|
||||
});
|
||||
} catch (e: any) {
|
||||
const msg = typeof e === "string" ? e : e?.message || "Unknown error";
|
||||
setErrorModal("Failed to send invite: " + msg);
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ export default function App() {
|
|||
{...backgroundFade}
|
||||
>
|
||||
<PanoramaBackground
|
||||
profile={selectedEdition.panorama}
|
||||
profile={selectedEdition?.panorama}
|
||||
isDay={displayIsDay}
|
||||
/>
|
||||
</motion.div>
|
||||
|
|
|
|||
|
|
@ -253,8 +253,12 @@ export class TauriService {
|
|||
return invoke("start_host_relay", { apiBaseUrl, accessToken, sessionId, gamePort });
|
||||
}
|
||||
|
||||
static async stopProxy(): Promise<void> {
|
||||
return invoke("stop_proxy");
|
||||
static async stopProxy(sessionId: string): Promise<void> {
|
||||
return invoke("stop_proxy", { sessionId });
|
||||
}
|
||||
|
||||
static async stopAllProxies(): Promise<void> {
|
||||
return invoke("stop_all_proxies");
|
||||
}
|
||||
|
||||
static async joinGame(
|
||||
|
|
|
|||
Loading…
Reference in a new issue