feat(ui): rebrand to G Launcher, add side server selector, update wallpaper and app icon, integrate GaCy-GO PS
No files matched your search
@@ -34,6 +34,7 @@
|
|||||||
| **Thai Mod Engine (ExcelData)** | ✅ | ✅ | ✅ | ⚠️ รอเกมจริง | `internal/language-service/thai-patch.go` มีระบบ `.backup` |
|
| **Thai Mod Engine (ExcelData)** | ✅ | ✅ | ✅ | ⚠️ รอเกมจริง | `internal/language-service/thai-patch.go` มีระบบ `.backup` |
|
||||||
| **Multi-Language (i18n)** | ✅ | ✅ | ✅ | ✅ | 6 ภาษา (`th`, `en`, `ja`, `ko`, `vi`, `zh`) ใน `frontend/public/locales/` |
|
| **Multi-Language (i18n)** | ✅ | ✅ | ✅ | ✅ | 6 ภาษา (`th`, `en`, `ja`, `ko`, `vi`, `zh`) ใน `frontend/public/locales/` |
|
||||||
| **Standalone Tool Extraction** | ✅ | ✅ | ✅ | ✅ | แตกไฟล์ `assets/` (`7za.exe`, `hpatchz.exe`, `zift.exe`) ลง `bin/` |
|
| **Standalone Tool Extraction** | ✅ | ✅ | ✅ | ✅ | แตกไฟล์ `assets/` (`7za.exe`, `hpatchz.exe`, `zift.exe`) ลง `bin/` |
|
||||||
|
| **Server Selection & GaCy PS** | ✅ | ✅ | ✅ | ✅ | ปุ่มเลือกเซิร์ฟเวอร์ด้านข้าง + ระบบดาวน์โหลด GaCy-GO (ZIP หรือ standalone sdk/server) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 361 KiB |
|
Before Width: | Height: | Size: 592 KiB After Width: | Height: | Size: 361 KiB |
@@ -30,6 +30,13 @@ export function DownloadServerProgress(version) {
|
|||||||
return $Call.ByID(1818966979, version);
|
return $Call.ByID(1818966979, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {$CancellablePromise<[string, string]>}
|
||||||
|
*/
|
||||||
|
export function FindServerExecutables() {
|
||||||
|
return $Call.ByID(1413748964);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {$CancellablePromise<[boolean, string, string]>}
|
* @returns {$CancellablePromise<[boolean, string, string]>}
|
||||||
*/
|
*/
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 305 KiB After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 361 KiB |
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"header": {
|
"header": {
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
"tools": "Tools",
|
"tools": "Tools",
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"minimize": "Minimize",
|
"minimize": "Minimize",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
"by": "Firefly Shelter"
|
"by": "GaCy"
|
||||||
},
|
},
|
||||||
"background": {
|
"background": {
|
||||||
"select_bg": "Select Background",
|
"select_bg": "Select Background",
|
||||||
@@ -50,14 +50,14 @@
|
|||||||
"launcher_label": "Launcher"
|
"launcher_label": "Launcher"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"header_title": "Firefly GO",
|
"header_title": "G Launcher",
|
||||||
"tooltip_how_to": "How to use all tools & commands",
|
"tooltip_how_to": "How to use all tools \u0026 commands",
|
||||||
"btn_select_game": "Select Game file",
|
"btn_select_game": "Select Game file",
|
||||||
"btn_selecting": "Selecting...",
|
"btn_selecting": "Selecting...",
|
||||||
"btn_start_game": "Start Game",
|
"btn_start_game": "Start Game",
|
||||||
"btn_game_running": "Game is running",
|
"btn_game_running": "Game is running",
|
||||||
"menu_change_path": "Change Game Path",
|
"menu_change_path": "Change Game Path",
|
||||||
"menu_check_update": "Check for Updates Server & Proxy",
|
"menu_check_update": "Check for Updates Server \u0026 Proxy",
|
||||||
"menu_open_server": "Open server folder",
|
"menu_open_server": "Open server folder",
|
||||||
"menu_open_proxy": "Open proxy folder",
|
"menu_open_proxy": "Open proxy folder",
|
||||||
"menu_open_voice": "Open voice folder",
|
"menu_open_voice": "Open voice folder",
|
||||||
@@ -102,9 +102,9 @@
|
|||||||
"modal_update_title": "Update Game",
|
"modal_update_title": "Update Game",
|
||||||
"status_wait": "Please wait...",
|
"status_wait": "Please wait...",
|
||||||
"inst_title": "📋 Instructions:",
|
"inst_title": "📋 Instructions:",
|
||||||
"inst_step_1": "1. Click \"Select Game Folder\" and choose your game's root directory",
|
"inst_step_1": "1. Click \"Select Game Folder\" and choose your game\u0027s root directory",
|
||||||
"inst_step_2": "2. Wait for the system to validate the game directory",
|
"inst_step_2": "2. Wait for the system to validate the game directory",
|
||||||
"inst_step_3": "3. Click \"Select Diff file Folder\" and choose your diff file's root directory",
|
"inst_step_3": "3. Click \"Select Diff file Folder\" and choose your diff file\u0027s root directory",
|
||||||
"inst_step_4": "4. Wait for the system to validate the diff file directory",
|
"inst_step_4": "4. Wait for the system to validate the diff file directory",
|
||||||
"inst_step_5": "5. Click \"Update Game\" to save your changes",
|
"inst_step_5": "5. Click \"Update Game\" to save your changes",
|
||||||
"toast_game_dir_not_found": "Game directory not found. Please select the correct folder.",
|
"toast_game_dir_not_found": "Game directory not found. Please select the correct folder.",
|
||||||
@@ -139,7 +139,7 @@
|
|||||||
"btn_apply": "Apply Language Settings",
|
"btn_apply": "Apply Language Settings",
|
||||||
"btn_applying": "Applying...",
|
"btn_applying": "Applying...",
|
||||||
"inst_title": "📋 Instructions:",
|
"inst_title": "📋 Instructions:",
|
||||||
"inst_step_1": "1. Click \"Select Game Folder\" and choose your game's root directory",
|
"inst_step_1": "1. Click \"Select Game Folder\" and choose your game\u0027s root directory",
|
||||||
"inst_step_2": "2. Wait for the system to validate the game directory",
|
"inst_step_2": "2. Wait for the system to validate the game directory",
|
||||||
"inst_step_3": "3. Select your preferred text and voice languages",
|
"inst_step_3": "3. Select your preferred text and voice languages",
|
||||||
"inst_step_4": "4. Click \"Apply Language Settings\" to save your changes",
|
"inst_step_4": "4. Click \"Apply Language Settings\" to save your changes",
|
||||||
@@ -156,10 +156,10 @@
|
|||||||
"sect1_launch_game": "Launch the game directly through the launcher with correct parameters and runtime environment.",
|
"sect1_launch_game": "Launch the game directly through the launcher with correct parameters and runtime environment.",
|
||||||
"sect1_lang_pre": "Support switching in-game language (e.g., EN, JP, ZH, KR) via",
|
"sect1_lang_pre": "Support switching in-game language (e.g., EN, JP, ZH, KR) via",
|
||||||
"sect1_lang_link": "Language Tools",
|
"sect1_lang_link": "Language Tools",
|
||||||
"sect1_patch_title": "Patch & Update Game Files",
|
"sect1_patch_title": "Patch \u0026 Update Game Files",
|
||||||
"sect1_patch_desc_1_pre": "Use the",
|
"sect1_patch_desc_1_pre": "Use the",
|
||||||
"sect1_patch_desc_1_link": "Diff Tool",
|
"sect1_patch_desc_1_link": "Diff Tool",
|
||||||
"sect1_patch_desc_1_post": "(DiffPatch) for fast & lightweight incremental updates.",
|
"sect1_patch_desc_1_post": "(DiffPatch) for fast \u0026 lightweight incremental updates.",
|
||||||
"sect1_patch_desc_2_pre": "Supports",
|
"sect1_patch_desc_2_pre": "Supports",
|
||||||
"sect1_patch_desc_2_post": ", and custom diff formats.",
|
"sect1_patch_desc_2_post": ", and custom diff formats.",
|
||||||
"sect2_title": "FireflyGo Chat Commands",
|
"sect2_title": "FireflyGo Chat Commands",
|
||||||
@@ -281,13 +281,13 @@
|
|||||||
"btn_back": "Back to Home"
|
"btn_back": "Back to Home"
|
||||||
},
|
},
|
||||||
"analysis": {
|
"analysis": {
|
||||||
"title": "Firefly Analysis & Veritas Plugin",
|
"title": "Firefly Analysis \u0026 Veritas Plugin",
|
||||||
"sect1_title": "About Veritas",
|
"sect1_title": "About Veritas",
|
||||||
"sect1_p1_pre": "Veritas",
|
"sect1_p1_pre": "Veritas",
|
||||||
"sect1_p1_mid": " is a powerful ",
|
"sect1_p1_mid": " is a powerful ",
|
||||||
"sect1_p1_highlight": "Damage Logger",
|
"sect1_p1_highlight": "Damage Logger",
|
||||||
"sect1_p1_post": " designed for analyzing damage in real-time during gameplay.",
|
"sect1_p1_post": " designed for analyzing damage in real-time during gameplay.",
|
||||||
"sect1_p2": "It's lightweight, fast, and easy to use for comprehensive damage analysis.",
|
"sect1_p2": "It\u0027s lightweight, fast, and easy to use for comprehensive damage analysis.",
|
||||||
"sect1_github": "GitHub Repository",
|
"sect1_github": "GitHub Repository",
|
||||||
"sect2_title": "Web Analysis Tools",
|
"sect2_title": "Web Analysis Tools",
|
||||||
"sect2_desc": "Use these web applications for real-time damage analysis with Veritas:",
|
"sect2_desc": "Use these web applications for real-time damage analysis with Veritas:",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"header": {
|
"header": {
|
||||||
"home": "ホーム",
|
"home": "ホーム",
|
||||||
"tools": "ツール",
|
"tools": "ツール",
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
"settings": "設定",
|
"settings": "設定",
|
||||||
"minimize": "最小化",
|
"minimize": "最小化",
|
||||||
"close": "閉じる",
|
"close": "閉じる",
|
||||||
"by": "Firefly Shelter"
|
"by": "GaCy"
|
||||||
},
|
},
|
||||||
"background": {
|
"background": {
|
||||||
"select_bg": "背景を選択",
|
"select_bg": "背景を選択",
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
"launcher_label": "Launcher"
|
"launcher_label": "Launcher"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"header_title": "Firefly GO",
|
"header_title": "G Launcher",
|
||||||
"tooltip_how_to": "ツールとコマンドの使い方",
|
"tooltip_how_to": "ツールとコマンドの使い方",
|
||||||
"btn_select_game": "ゲームファイルを選択",
|
"btn_select_game": "ゲームファイルを選択",
|
||||||
"btn_selecting": "選択中...",
|
"btn_selecting": "選択中...",
|
||||||
@@ -281,7 +281,7 @@
|
|||||||
"btn_back": "ホームに戻る"
|
"btn_back": "ホームに戻る"
|
||||||
},
|
},
|
||||||
"analysis": {
|
"analysis": {
|
||||||
"title": "Firefly 分析 & Veritas プラグイン",
|
"title": "Firefly 分析 \u0026 Veritas プラグイン",
|
||||||
"sect1_title": "Veritas について",
|
"sect1_title": "Veritas について",
|
||||||
"sect1_p1_pre": "Veritas",
|
"sect1_p1_pre": "Veritas",
|
||||||
"sect1_p1_mid": " は、ゲームプレイ中のダメージをリアルタイムで分析するために設計された強力な ",
|
"sect1_p1_mid": " は、ゲームプレイ中のダメージをリアルタイムで分析するために設計された強力な ",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"header": {
|
"header": {
|
||||||
"home": "홈",
|
"home": "홈",
|
||||||
"tools": "도구",
|
"tools": "도구",
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
"settings": "설정",
|
"settings": "설정",
|
||||||
"minimize": "최소화",
|
"minimize": "최소화",
|
||||||
"close": "닫기",
|
"close": "닫기",
|
||||||
"by": "Firefly Shelter"
|
"by": "GaCy"
|
||||||
},
|
},
|
||||||
"background": {
|
"background": {
|
||||||
"select_bg": "배경 선택",
|
"select_bg": "배경 선택",
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
"launcher_label": "Launcher"
|
"launcher_label": "Launcher"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"header_title": "Firefly GO",
|
"header_title": "G Launcher",
|
||||||
"tooltip_how_to": "도구 및 명령 사용법",
|
"tooltip_how_to": "도구 및 명령 사용법",
|
||||||
"btn_select_game": "게임 파일 선택",
|
"btn_select_game": "게임 파일 선택",
|
||||||
"btn_selecting": "선택 중...",
|
"btn_selecting": "선택 중...",
|
||||||
@@ -281,7 +281,7 @@
|
|||||||
"btn_back": "홈으로 돌아가기"
|
"btn_back": "홈으로 돌아가기"
|
||||||
},
|
},
|
||||||
"analysis": {
|
"analysis": {
|
||||||
"title": "Firefly 분석 & Veritas 플러그인",
|
"title": "Firefly 분석 \u0026 Veritas 플러그인",
|
||||||
"sect1_title": "Veritas 소개",
|
"sect1_title": "Veritas 소개",
|
||||||
"sect1_p1_pre": "Veritas",
|
"sect1_p1_pre": "Veritas",
|
||||||
"sect1_p1_mid": "는 게임 플레이 중 실시간으로 피해량을 분석하도록 설계된 강력한 ",
|
"sect1_p1_mid": "는 게임 플레이 중 실시간으로 피해량을 분석하도록 설계된 강력한 ",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"header": {
|
"header": {
|
||||||
"home": "หน้าแรก",
|
"home": "หน้าแรก",
|
||||||
"tools": "เครื่องมือ",
|
"tools": "เครื่องมือ",
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
"btn_start_game": "เริ่มเกม",
|
"btn_start_game": "เริ่มเกม",
|
||||||
"btn_game_running": "เกมกำลังทำงานอยู่",
|
"btn_game_running": "เกมกำลังทำงานอยู่",
|
||||||
"menu_change_path": "เปลี่ยนโฟลเดอร์เกม",
|
"menu_change_path": "เปลี่ยนโฟลเดอร์เกม",
|
||||||
"menu_check_update": "ตรวจสอบอัปเดตเซิร์ฟเวอร์ & พร็อกซี",
|
"menu_check_update": "ตรวจสอบอัปเดตเซิร์ฟเวอร์ \u0026 พร็อกซี",
|
||||||
"menu_open_server": "เปิดโฟลเดอร์เซิร์ฟเวอร์",
|
"menu_open_server": "เปิดโฟลเดอร์เซิร์ฟเวอร์",
|
||||||
"menu_open_proxy": "เปิดโฟลเดอร์พร็อกซี",
|
"menu_open_proxy": "เปิดโฟลเดอร์พร็อกซี",
|
||||||
"menu_open_voice": "เปิดโฟลเดอร์เสียงพากย์",
|
"menu_open_voice": "เปิดโฟลเดอร์เสียงพากย์",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"header": {
|
"header": {
|
||||||
"home": "Trang chủ",
|
"home": "Trang chủ",
|
||||||
"tools": "Công cụ",
|
"tools": "Công cụ",
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
"settings": "Cài đặt",
|
"settings": "Cài đặt",
|
||||||
"minimize": "Thu nhỏ",
|
"minimize": "Thu nhỏ",
|
||||||
"close": "Đóng",
|
"close": "Đóng",
|
||||||
"by": "Firefly Shelter"
|
"by": "GaCy"
|
||||||
},
|
},
|
||||||
"background": {
|
"background": {
|
||||||
"select_bg": "Chọn nền",
|
"select_bg": "Chọn nền",
|
||||||
@@ -50,14 +50,14 @@
|
|||||||
"launcher_label": "Launcher"
|
"launcher_label": "Launcher"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"header_title": "Firefly GO",
|
"header_title": "G Launcher",
|
||||||
"tooltip_how_to": "Cách sử dụng công cụ & lệnh",
|
"tooltip_how_to": "Cách sử dụng công cụ \u0026 lệnh",
|
||||||
"btn_select_game": "Chọn tệp Game",
|
"btn_select_game": "Chọn tệp Game",
|
||||||
"btn_selecting": "Đang chọn...",
|
"btn_selecting": "Đang chọn...",
|
||||||
"btn_start_game": "Bắt đầu Game",
|
"btn_start_game": "Bắt đầu Game",
|
||||||
"btn_game_running": "Game đang chạy",
|
"btn_game_running": "Game đang chạy",
|
||||||
"menu_change_path": "Thay đổi đường dẫn Game",
|
"menu_change_path": "Thay đổi đường dẫn Game",
|
||||||
"menu_check_update": "Kiểm tra cập nhật Server & Proxy",
|
"menu_check_update": "Kiểm tra cập nhật Server \u0026 Proxy",
|
||||||
"menu_open_server": "Mở thư mục Server",
|
"menu_open_server": "Mở thư mục Server",
|
||||||
"menu_open_proxy": "Mở thư mục Proxy",
|
"menu_open_proxy": "Mở thư mục Proxy",
|
||||||
"menu_open_voice": "Mở thư mục Voice",
|
"menu_open_voice": "Mở thư mục Voice",
|
||||||
@@ -156,10 +156,10 @@
|
|||||||
"sect1_launch_game": "Khởi chạy game trực tiếp thông qua launcher với các thông số và môi trường chạy chính xác.",
|
"sect1_launch_game": "Khởi chạy game trực tiếp thông qua launcher với các thông số và môi trường chạy chính xác.",
|
||||||
"sect1_lang_pre": "Hỗ trợ chuyển đổi ngôn ngữ trong game (ví dụ: EN, JP, ZH, KR) qua",
|
"sect1_lang_pre": "Hỗ trợ chuyển đổi ngôn ngữ trong game (ví dụ: EN, JP, ZH, KR) qua",
|
||||||
"sect1_lang_link": "Công cụ Ngôn ngữ",
|
"sect1_lang_link": "Công cụ Ngôn ngữ",
|
||||||
"sect1_patch_title": "Vá & Cập nhật Tệp Game",
|
"sect1_patch_title": "Vá \u0026 Cập nhật Tệp Game",
|
||||||
"sect1_patch_desc_1_pre": "Sử dụng",
|
"sect1_patch_desc_1_pre": "Sử dụng",
|
||||||
"sect1_patch_desc_1_link": "Công cụ Diff",
|
"sect1_patch_desc_1_link": "Công cụ Diff",
|
||||||
"sect1_patch_desc_1_post": "(DiffPatch) để cập nhật gia tăng nhanh chóng & nhẹ nhàng.",
|
"sect1_patch_desc_1_post": "(DiffPatch) để cập nhật gia tăng nhanh chóng \u0026 nhẹ nhàng.",
|
||||||
"sect1_patch_desc_2_pre": "Hỗ trợ",
|
"sect1_patch_desc_2_pre": "Hỗ trợ",
|
||||||
"sect1_patch_desc_2_post": "và các định dạng diff tùy chỉnh.",
|
"sect1_patch_desc_2_post": "và các định dạng diff tùy chỉnh.",
|
||||||
"sect2_title": "Lệnh Chat FireflyGo",
|
"sect2_title": "Lệnh Chat FireflyGo",
|
||||||
@@ -281,7 +281,7 @@
|
|||||||
"btn_back": "Trở về Trang chủ"
|
"btn_back": "Trở về Trang chủ"
|
||||||
},
|
},
|
||||||
"analysis": {
|
"analysis": {
|
||||||
"title": "Phân tích Firefly & Plugin Veritas",
|
"title": "Phân tích Firefly \u0026 Plugin Veritas",
|
||||||
"sect1_title": "Về Veritas",
|
"sect1_title": "Về Veritas",
|
||||||
"sect1_p1_pre": "",
|
"sect1_p1_pre": "",
|
||||||
"sect1_p1_mid": " là một ",
|
"sect1_p1_mid": " là một ",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"header": {
|
"header": {
|
||||||
"home": "首页",
|
"home": "首页",
|
||||||
"tools": "工具",
|
"tools": "工具",
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
"settings": "设置",
|
"settings": "设置",
|
||||||
"minimize": "最小化",
|
"minimize": "最小化",
|
||||||
"close": "关闭",
|
"close": "关闭",
|
||||||
"by": "Firefly Shelter"
|
"by": "GaCy"
|
||||||
},
|
},
|
||||||
"background": {
|
"background": {
|
||||||
"select_bg": "选择背景",
|
"select_bg": "选择背景",
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
"launcher_label": "Launcher"
|
"launcher_label": "Launcher"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"header_title": "Firefly GO",
|
"header_title": "G Launcher",
|
||||||
"tooltip_how_to": "如何使用工具与命令",
|
"tooltip_how_to": "如何使用工具与命令",
|
||||||
"btn_select_game": "选择游戏文件",
|
"btn_select_game": "选择游戏文件",
|
||||||
"btn_selecting": "正在选择...",
|
"btn_selecting": "正在选择...",
|
||||||
@@ -281,7 +281,7 @@
|
|||||||
"btn_back": "返回主页"
|
"btn_back": "返回主页"
|
||||||
},
|
},
|
||||||
"analysis": {
|
"analysis": {
|
||||||
"title": "Firefly 分析 & Veritas 插件",
|
"title": "Firefly 分析 \u0026 Veritas 插件",
|
||||||
"sect1_title": "关于 Veritas",
|
"sect1_title": "关于 Veritas",
|
||||||
"sect1_p1_pre": "Veritas",
|
"sect1_p1_pre": "Veritas",
|
||||||
"sect1_p1_mid": " 是一款强大的",
|
"sect1_p1_mid": " 是一款强大的",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Link } from "@tanstack/react-router";
|
import { Link } from "@tanstack/react-router";
|
||||||
import useModalStore from "@/stores/modalStore";
|
import useModalStore from "@/stores/modalStore";
|
||||||
import { Blend, BookOpen, Diff, Home, Info, Languages, Minus, Puzzle, Settings, TrendingUpDown, Wrench, X } from "lucide-react";
|
import { Blend, BookOpen, Diff, Home, Info, Languages, Minus, Puzzle, Settings, TrendingUpDown, Wrench, X } from "lucide-react";
|
||||||
import { AppService } from "@bindings/g-launcher/internal/app-service";
|
import { AppService } from "@bindings/g-launcher/internal/app-service";
|
||||||
|
|||||||
@@ -9,7 +9,15 @@ export async function CheckUpdateServer(
|
|||||||
serverVersion: string
|
serverVersion: string
|
||||||
): Promise<{ isUpdate: boolean; isExists: boolean; version: string }> {
|
): Promise<{ isUpdate: boolean; isExists: boolean; version: string }> {
|
||||||
const [ok, latestVersion, error] = await GitService.GetLatestServerVersion()
|
const [ok, latestVersion, error] = await GitService.GetLatestServerVersion()
|
||||||
const isExists = await FSService.FileExists(serverPath)
|
let isExists = await FSService.FileExists(serverPath)
|
||||||
|
|
||||||
|
if (!isExists) {
|
||||||
|
const [gameServer] = await GitService.FindServerExecutables()
|
||||||
|
if (gameServer) {
|
||||||
|
useSettingStore.getState().setServerPath(gameServer)
|
||||||
|
isExists = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
toast.error("Server error: " + error)
|
toast.error("Server error: " + error)
|
||||||
@@ -23,15 +31,18 @@ export async function CheckUpdateServer(
|
|||||||
|
|
||||||
export async function UpdateServer(serverVersion: string) : Promise<void> {
|
export async function UpdateServer(serverVersion: string) : Promise<void> {
|
||||||
const {setDownloadType } = useLauncherStore.getState()
|
const {setDownloadType } = useLauncherStore.getState()
|
||||||
const {setServerPath, setServerVersion} = useSettingStore.getState()
|
const {setServerPath, setSdkServerPath, setServerVersion} = useSettingStore.getState()
|
||||||
setDownloadType("Downloading server...")
|
setDownloadType("Downloading GaCy PS server...")
|
||||||
const [ok, error] = await GitService.DownloadServerProgress(serverVersion)
|
const [ok, error] = await GitService.DownloadServerProgress(serverVersion)
|
||||||
if (ok) {
|
if (ok) {
|
||||||
setDownloadType("Unzipping server...")
|
setDownloadType("Configuring server files...")
|
||||||
GitService.UnzipServer()
|
const [gameServer, sdkServer] = await GitService.FindServerExecutables()
|
||||||
setDownloadType("Download server successfully")
|
setDownloadType("Download server successfully")
|
||||||
setServerVersion(serverVersion)
|
setServerVersion(serverVersion)
|
||||||
setServerPath("./server/firefly-go_win.exe")
|
setServerPath(gameServer || "./server/gameserver-go.exe")
|
||||||
|
if (sdkServer) {
|
||||||
|
setSdkServerPath(sdkServer)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
toast.error(error)
|
toast.error(error)
|
||||||
setDownloadType("Download server failed")
|
setDownloadType("Download server failed")
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { Play, Menu, FolderOpen, MessageCircleQuestionMark } from 'lucide-react';
|
import { Play, Menu, FolderOpen, MessageCircleQuestionMark, Server, Globe, CheckCircle2 } from 'lucide-react';
|
||||||
import { AppService } from '@bindings/g-launcher/internal/app-service';
|
import { AppService } from '@bindings/g-launcher/internal/app-service';
|
||||||
import { FSService } from '@bindings/g-launcher/internal/fs-service';
|
import { FSService } from '@bindings/g-launcher/internal/fs-service';
|
||||||
|
import { GitService } from '@bindings/g-launcher/internal/git-service';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import path from 'path-browserify'
|
import path from 'path-browserify'
|
||||||
import useSettingStore from '@/stores/settingStore';
|
import useSettingStore from '@/stores/settingStore';
|
||||||
@@ -21,11 +22,16 @@ export default function LauncherPage() {
|
|||||||
setGamePath,
|
setGamePath,
|
||||||
setGameDir,
|
setGameDir,
|
||||||
serverPath,
|
serverPath,
|
||||||
|
setServerPath,
|
||||||
|
sdkServerPath,
|
||||||
|
setSdkServerPath,
|
||||||
proxyPath,
|
proxyPath,
|
||||||
gameDir,
|
gameDir,
|
||||||
serverVersion,
|
serverVersion,
|
||||||
proxyVersion,
|
proxyVersion,
|
||||||
background
|
background,
|
||||||
|
selectedServer,
|
||||||
|
setSelectedServer
|
||||||
} = useSettingStore()
|
} = useSettingStore()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const {
|
const {
|
||||||
@@ -40,8 +46,6 @@ export default function LauncherPage() {
|
|||||||
const {
|
const {
|
||||||
isLoading,
|
isLoading,
|
||||||
downloadType,
|
downloadType,
|
||||||
serverReady,
|
|
||||||
proxyReady,
|
|
||||||
isDownloading,
|
isDownloading,
|
||||||
serverRunning,
|
serverRunning,
|
||||||
proxyRunning,
|
proxyRunning,
|
||||||
@@ -49,7 +53,6 @@ export default function LauncherPage() {
|
|||||||
progressDownload,
|
progressDownload,
|
||||||
downloadSpeed,
|
downloadSpeed,
|
||||||
updateData,
|
updateData,
|
||||||
// launcherVersion,
|
|
||||||
setLauncherVersion,
|
setLauncherVersion,
|
||||||
setIsLoading,
|
setIsLoading,
|
||||||
setDownloadType,
|
setDownloadType,
|
||||||
@@ -64,13 +67,13 @@ export default function LauncherPage() {
|
|||||||
|
|
||||||
const widgetLinks = [
|
const widgetLinks = [
|
||||||
{
|
{
|
||||||
tooltip: "Firefly SRAnalysis",
|
tooltip: "SRAnalysis",
|
||||||
href: "https://sranalysis.punklorde.org",
|
href: "https://sranalysis.punklorde.org",
|
||||||
img: "https://sranalysis.punklorde.org/ff-sranalysis.png",
|
img: "https://sranalysis.punklorde.org/ff-sranalysis.png",
|
||||||
btnClass: "btn-primary"
|
btnClass: "btn-primary"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tooltip: "Firefly SRTools",
|
tooltip: "SRTools",
|
||||||
href: "https://srtools.punklorde.org",
|
href: "https://srtools.punklorde.org",
|
||||||
img: "https://srtools.punklorde.org/ff-srtool.png",
|
img: "https://srtools.punklorde.org/ff-srtool.png",
|
||||||
btnClass: "btn-secondary"
|
btnClass: "btn-secondary"
|
||||||
@@ -91,7 +94,18 @@ export default function LauncherPage() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverExists = await FSService.FileExists(serverPath)
|
let serverExists = await FSService.FileExists(serverPath)
|
||||||
|
if (!serverExists) {
|
||||||
|
const [gameServer, sdkServer] = await GitService.FindServerExecutables()
|
||||||
|
if (gameServer) {
|
||||||
|
setServerPath(gameServer)
|
||||||
|
serverExists = true
|
||||||
|
}
|
||||||
|
if (sdkServer) {
|
||||||
|
setSdkServerPath(sdkServer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const proxyExists = await FSService.FileExists(proxyPath)
|
const proxyExists = await FSService.FileExists(proxyPath)
|
||||||
setServerReady(serverExists)
|
setServerReady(serverExists)
|
||||||
setProxyReady(proxyExists)
|
setProxyReady(proxyExists)
|
||||||
@@ -121,17 +135,10 @@ export default function LauncherPage() {
|
|||||||
proxy: proxyData,
|
proxy: proxyData,
|
||||||
launcher: launcherData
|
launcher: launcherData
|
||||||
})
|
})
|
||||||
const exitGame = await FSService.FileExists(gamePath)
|
|
||||||
if (!exitGame) {
|
|
||||||
setGameRunning(false)
|
|
||||||
setGamePath("")
|
|
||||||
setGameDir("")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!serverData.isExists || !proxyData.isExists) {
|
if (!serverData.isExists || !proxyData.isExists) {
|
||||||
setServerReady(false)
|
setServerReady(false)
|
||||||
setProxyReady(false)
|
setProxyReady(false)
|
||||||
setIsOpenDownloadDataModal(true)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +182,7 @@ export default function LauncherPage() {
|
|||||||
|
|
||||||
const handleStartGame = async () => {
|
const handleStartGame = async () => {
|
||||||
if (!gamePath) {
|
if (!gamePath) {
|
||||||
|
toast.info("Please select the game executable first")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (gameRunning) {
|
if (gameRunning) {
|
||||||
@@ -182,36 +190,59 @@ export default function LauncherPage() {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
|
||||||
|
if (selectedServer === "gacy-ps") {
|
||||||
|
const [gameServer, sdkServer] = await GitService.FindServerExecutables()
|
||||||
|
const activeServer = gameServer || serverPath
|
||||||
|
|
||||||
|
if (!activeServer) {
|
||||||
|
toast.error("Please download GaCy PS server files first")
|
||||||
|
setIsOpenDownloadDataModal(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Start Proxy
|
||||||
|
const activeProxy = proxyPath || "./proxy/firefly-go-proxy.exe"
|
||||||
if (!proxyRunning && !gamePath.endsWith("launcher.exe")) {
|
if (!proxyRunning && !gamePath.endsWith("launcher.exe")) {
|
||||||
const [resultProxy, error] = await FSService.StartWithConsole(proxyPath)
|
const [resultProxy, error] = await FSService.StartWithConsole(activeProxy)
|
||||||
if (!resultProxy) {
|
if (!resultProxy) {
|
||||||
toast.error(t("home.toast_start_proxy_failed") + error)
|
toast.error(t("home.toast_start_proxy_failed") + ": " + error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setProxyRunning(true)
|
setProxyRunning(true)
|
||||||
}
|
}
|
||||||
await sleep(500)
|
await sleep(500)
|
||||||
|
|
||||||
|
// 2. Start SDK Server if exists
|
||||||
|
const activeSdk = sdkServer || sdkServerPath
|
||||||
|
if (activeSdk) {
|
||||||
|
await FSService.StartWithConsole(activeSdk)
|
||||||
|
await sleep(400)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Start Game Server
|
||||||
if (!serverRunning) {
|
if (!serverRunning) {
|
||||||
const [resultServer, error] = await FSService.StartWithConsole(serverPath)
|
const [resultServer, error] = await FSService.StartWithConsole(activeServer)
|
||||||
if (!resultServer) {
|
if (!resultServer) {
|
||||||
toast.error(t("home.toast_start_server_failed") + error)
|
toast.error(t("home.toast_start_server_failed") + ": " + error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setServerRunning(true)
|
setServerRunning(true)
|
||||||
}
|
}
|
||||||
await sleep(1000)
|
await sleep(1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Start Game
|
||||||
if (gamePath.endsWith("launcher.exe")) {
|
if (gamePath.endsWith("launcher.exe")) {
|
||||||
const [resultGame, error] = await FSService.StartWithConsole(gamePath)
|
const [resultGame, error] = await FSService.StartWithConsole(gamePath)
|
||||||
if (!resultGame) {
|
if (!resultGame) {
|
||||||
toast.error(t("home.toast_start_game_failed") + error)
|
toast.error(t("home.toast_start_game_failed") + ": " + error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const [resultGame, error] = await FSService.StartApp(gamePath)
|
const [resultGame, error] = await FSService.StartApp(gamePath)
|
||||||
if (!resultGame) {
|
if (!resultGame) {
|
||||||
toast.error(t("home.toast_start_game_failed") + error)
|
toast.error(t("home.toast_start_game_failed") + ": " + error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,58 +297,116 @@ export default function LauncherPage() {
|
|||||||
return (
|
return (
|
||||||
<div className="relative min-h-fit overflow-hidden">
|
<div className="relative min-h-fit overflow-hidden">
|
||||||
<img
|
<img
|
||||||
src={background}
|
src={background || "bg-1.jpeg"}
|
||||||
alt="background"
|
alt="background"
|
||||||
className="fixed inset-0 w-full h-full object-cover z-0"
|
className="fixed inset-0 w-full h-full object-cover z-0"
|
||||||
onError={(e) => {
|
onError={(e) => {
|
||||||
const target = e.currentTarget as HTMLImageElement
|
const target = e.currentTarget as HTMLImageElement
|
||||||
target.src = "bg-12.jpg"
|
target.src = "bg-1.jpeg"
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Header */}
|
{/* Header Title */}
|
||||||
<header className="hidden sm:flex fixed z-10 items-center justify-between py-6 px-4">
|
<header className="hidden sm:flex fixed z-10 items-center justify-between py-6 px-4">
|
||||||
<div className="text-2xl font-bold text-white bg-gray-500/5 rounded-full p-1">{t("home.header_title")}</div>
|
<div className="text-2xl font-black tracking-wide text-white bg-black/40 backdrop-blur-md rounded-2xl px-4 py-1.5 border border-white/10 shadow-lg">
|
||||||
|
<span className="text-cyan-400">G</span> Launcher
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div className="hidden sm:flex fixed top-1/4 right-4 z-10 flex-col space-y-3 bg-white/5 rounded-xl p-3 shadow-lg">
|
{/* Side Server Selector */}
|
||||||
|
<div className="hidden sm:flex fixed top-1/4 right-5 z-20 flex-col items-end gap-3">
|
||||||
|
<div className="text-[11px] uppercase tracking-wider font-bold text-white/80 bg-black/50 backdrop-blur-md px-3.5 py-1 rounded-full border border-white/15 shadow-sm">
|
||||||
|
เลือกเซิร์ฟเวอร์ (Select Server)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Server Option 1: GaCy PS */}
|
||||||
|
<button
|
||||||
|
onClick={() => setSelectedServer("gacy-ps")}
|
||||||
|
className={`flex items-center gap-3 w-64 p-3 rounded-2xl backdrop-blur-md transition-all duration-200 border cursor-pointer ${
|
||||||
|
selectedServer === "gacy-ps"
|
||||||
|
? "bg-cyan-500/30 border-cyan-400 text-white shadow-xl shadow-cyan-500/20 ring-2 ring-cyan-400"
|
||||||
|
: "bg-black/55 border-white/15 text-white/80 hover:bg-black/75 hover:border-cyan-400/50"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className={`p-2.5 rounded-xl ${selectedServer === "gacy-ps" ? "bg-cyan-500 text-black font-bold" : "bg-cyan-500/20 text-cyan-400"}`}>
|
||||||
|
<Server className="w-5 h-5" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col text-left flex-1 min-w-0">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span className="font-bold text-sm tracking-tight truncate">GaCy PS</span>
|
||||||
|
<span className="badge badge-xs badge-info font-mono text-[10px]">4.6.54</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-xs text-white/60 truncate">Private Server (Local)</span>
|
||||||
|
</div>
|
||||||
|
{selectedServer === "gacy-ps" && (
|
||||||
|
<CheckCircle2 className="w-5 h-5 text-cyan-400 shrink-0" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Server Option 2: Official Server */}
|
||||||
|
<button
|
||||||
|
onClick={() => setSelectedServer("official")}
|
||||||
|
className={`flex items-center gap-3 w-64 p-3 rounded-2xl backdrop-blur-md transition-all duration-200 border cursor-pointer ${
|
||||||
|
selectedServer === "official"
|
||||||
|
? "bg-emerald-500/30 border-emerald-400 text-white shadow-xl shadow-emerald-500/20 ring-2 ring-emerald-400"
|
||||||
|
: "bg-black/55 border-white/15 text-white/80 hover:bg-black/75 hover:border-emerald-400/50"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className={`p-2.5 rounded-xl ${selectedServer === "official" ? "bg-emerald-500 text-black font-bold" : "bg-emerald-500/20 text-emerald-400"}`}>
|
||||||
|
<Globe className="w-5 h-5" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col text-left flex-1 min-w-0">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<span className="font-bold text-sm tracking-tight truncate">Official Server</span>
|
||||||
|
<span className="badge badge-xs badge-success font-mono text-[10px]">Live</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-xs text-white/60 truncate">Hoyoverse Official</span>
|
||||||
|
</div>
|
||||||
|
{selectedServer === "official" && (
|
||||||
|
<CheckCircle2 className="w-5 h-5 text-emerald-400 shrink-0" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* External Tools Mini Bar */}
|
||||||
|
<div className="flex items-center gap-2 pt-2">
|
||||||
{widgetLinks.map((link, idx) => (
|
{widgetLinks.map((link, idx) => (
|
||||||
<div key={idx} className="tooltip tooltip-left" data-tip={link.tooltip}>
|
<div key={idx} className="tooltip tooltip-bottom" data-tip={link.tooltip}>
|
||||||
<a
|
<a
|
||||||
className={`btn btn-circle ${link.btnClass}`}
|
className="btn btn-circle btn-sm bg-black/50 border-white/20 hover:border-cyan-400"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
href={link.href}
|
href={link.href}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={link.img}
|
src={link.img}
|
||||||
alt={link.tooltip}
|
alt={link.tooltip}
|
||||||
className="w-8 h-8 rounded-full"
|
className="w-5 h-5 rounded-full"
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
<div className="tooltip tooltip-bottom" data-tip={t("home.tooltip_how_to")}>
|
||||||
<div className="tooltip tooltip-left" data-tip={t("home.tooltip_how_to")}>
|
|
||||||
<Link
|
<Link
|
||||||
to="/howto"
|
to="/howto"
|
||||||
className="btn btn-warning btn-circle"
|
className="btn btn-circle btn-sm btn-warning"
|
||||||
>
|
>
|
||||||
<MessageCircleQuestionMark className="w-6 h-6 font-bold rounded-full" />
|
<MessageCircleQuestionMark className="w-4 h-4 font-bold rounded-full" />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Left Background Selector */}
|
||||||
<div className="hidden sm:flex fixed top-1/2 left-5 z-10">
|
<div className="hidden sm:flex fixed top-1/2 left-5 z-10">
|
||||||
<BackgroundSelector />
|
<BackgroundSelector />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Bottom Panel */}
|
{/* Bottom Play Panel: Appears once a server is selected! */}
|
||||||
{serverReady && proxyReady && !isDownloading && (
|
{selectedServer !== "" && !isDownloading && (
|
||||||
<div className="fixed bottom-0 right-0 p-8 z-2">
|
<div className="fixed bottom-0 right-0 p-8 z-2 animate-in fade-in slide-in-from-bottom-4 duration-300">
|
||||||
<div className="flex flex-wrap items-center justify-center gap-2">
|
<div className="flex flex-wrap items-center justify-center gap-2">
|
||||||
{gamePath === "" ? (
|
{gamePath === "" ? (
|
||||||
<button
|
<button
|
||||||
className="btn btn-accent btn-xl font-bold"
|
className="btn btn-accent btn-xl font-bold shadow-xl"
|
||||||
onClick={handlePickFile}
|
onClick={handlePickFile}
|
||||||
>
|
>
|
||||||
<FolderOpen className="w-6 h-6" />
|
<FolderOpen className="w-6 h-6" />
|
||||||
@@ -325,19 +414,27 @@ export default function LauncherPage() {
|
|||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
className="btn btn-warning btn-xl font-bold"
|
className={`btn btn-xl font-bold shadow-2xl transition-all ${
|
||||||
|
selectedServer === "gacy-ps"
|
||||||
|
? "btn-warning text-black hover:brightness-110"
|
||||||
|
: "btn-success text-white hover:brightness-110"
|
||||||
|
}`}
|
||||||
onClick={handleStartGame}
|
onClick={handleStartGame}
|
||||||
>
|
>
|
||||||
<Play className="w-6 h-6" />
|
<Play className="w-6 h-6 fill-current" />
|
||||||
{isLoading ? t("home.btn_selecting") : gameRunning ? t("home.btn_game_running") : t("home.btn_start_game")}
|
{isLoading
|
||||||
|
? t("home.btn_selecting")
|
||||||
|
: gameRunning
|
||||||
|
? t("home.btn_game_running")
|
||||||
|
: `${t("home.btn_start_game")} [${selectedServer === "gacy-ps" ? "GaCy PS" : "Official"}]`}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="dropdown dropdown-top dropdown-end">
|
<div className="dropdown dropdown-top dropdown-end">
|
||||||
<div tabIndex={0} role="button" className="btn btn-black btn-circle btn-xl m-1">
|
<div tabIndex={0} role="button" className="btn btn-black btn-circle btn-xl m-1 border border-white/20 shadow-xl">
|
||||||
<Menu className="w-6 h-6" />
|
<Menu className="w-6 h-6" />
|
||||||
</div>
|
</div>
|
||||||
<ul tabIndex={0} className="dropdown-content menu bg-base-100 rounded-box z-1 w-52 p-2 shadow-sm">
|
<ul tabIndex={0} className="dropdown-content menu bg-black/80 backdrop-blur-md rounded-box z-1 w-56 p-2 shadow-2xl border border-white/10 text-white">
|
||||||
<li><button onClick={handlePickFile}>{t("home.menu_change_path")}</button></li>
|
<li><button onClick={handlePickFile}>{t("home.menu_change_path")}</button></li>
|
||||||
<li>
|
<li>
|
||||||
<button
|
<button
|
||||||
@@ -364,23 +461,16 @@ export default function LauncherPage() {
|
|||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
<button onClick={() => {
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<button disabled={!serverPath} onClick={() => {
|
|
||||||
if (serverPath) {
|
|
||||||
FSService.OpenFolder("./server")
|
FSService.OpenFolder("./server")
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("home.menu_open_server")}
|
{t("home.menu_open_server")}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<button disabled={!proxyPath} onClick={() => {
|
<button onClick={() => {
|
||||||
if (proxyPath) {
|
|
||||||
FSService.OpenFolder("./proxy")
|
FSService.OpenFolder("./proxy")
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("home.menu_open_proxy")}
|
{t("home.menu_open_proxy")}
|
||||||
@@ -397,20 +487,27 @@ export default function LauncherPage() {
|
|||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Downloading */}
|
{/* Notification when no server is selected yet */}
|
||||||
|
{selectedServer === "" && !isDownloading && (
|
||||||
|
<div className="fixed bottom-8 right-8 z-2 flex items-center gap-2 bg-black/60 backdrop-blur-md px-5 py-3 rounded-2xl border border-white/20 text-white shadow-xl animate-pulse">
|
||||||
|
<span className="text-cyan-400 text-lg">👉</span>
|
||||||
|
<span className="text-sm font-medium">กรุณาเลือกเซิร์ฟเวอร์ด้านบนเพื่อเริ่มเล่น (Select a server to play)</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Downloading Progress Bar */}
|
||||||
{isDownloading && (
|
{isDownloading && (
|
||||||
updateData.proxy.isUpdate
|
updateData.proxy.isUpdate
|
||||||
|| updateData.server.isUpdate
|
|| updateData.server.isUpdate
|
||||||
|| !updateData.proxy.isExists
|
|| !updateData.proxy.isExists
|
||||||
|| !updateData.server.isExists
|
|| !updateData.server.isExists
|
||||||
) && (
|
) && (
|
||||||
<div className="fixed bottom-4 left-1/2 transform -translate-x-1/2 z-10 w-[60vw] bg-black/20 backdrop-blur-sm rounded-lg p-4 shadow-lg">
|
<div className="fixed bottom-4 left-1/2 transform -translate-x-1/2 z-10 w-[60vw] bg-black/60 backdrop-blur-md rounded-2xl p-4 shadow-2xl border border-white/10">
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="flex justify-center items-center text-sm text-white/80">
|
<div className="flex justify-center items-center text-sm text-white/80">
|
||||||
<span>{downloadType}</span>
|
<span>{downloadType}</span>
|
||||||
@@ -434,8 +531,9 @@ export default function LauncherPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Launcher Self Update Bar */}
|
||||||
{isDownloading && updateData.launcher.isUpdate && (
|
{isDownloading && updateData.launcher.isUpdate && (
|
||||||
<div className="fixed bottom-4 left-1/2 transform -translate-x-1/2 z-10 w-[60vw] bg-black/20 backdrop-blur-sm rounded-lg p-4 shadow-lg">
|
<div className="fixed bottom-4 left-1/2 transform -translate-x-1/2 z-10 w-[60vw] bg-black/60 backdrop-blur-md rounded-2xl p-4 shadow-2xl border border-white/10">
|
||||||
<div className="space-y-3 text-sm text-white/80 text-center">
|
<div className="space-y-3 text-sm text-white/80 text-center">
|
||||||
{["update:launcher:downloading", "update:launcher:success", "update:launcher:failed"].includes(downloadType) && (
|
{["update:launcher:downloading", "update:launcher:success", "update:launcher:failed"].includes(downloadType) && (
|
||||||
<div className="flex justify-center items-center gap-4 ml-4">
|
<div className="flex justify-center items-center gap-4 ml-4">
|
||||||
@@ -477,12 +575,7 @@ export default function LauncherPage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="hidden md:block fixed bottom-4 left-5 z-10">
|
{/* Modals */}
|
||||||
|
|
||||||
<img src="/heart-hsr.gif" alt="firefly animation" className="rounded-lg w-24 h-24" />
|
|
||||||
|
|
||||||
</div>
|
|
||||||
{/* Modal */}
|
|
||||||
<UpdateModal
|
<UpdateModal
|
||||||
isOpen={isOpenUpdateDataModal}
|
isOpen={isOpenUpdateDataModal}
|
||||||
onClose={() => setIsOpenUpdateDataModal(false)}
|
onClose={() => setIsOpenUpdateDataModal(false)}
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ interface SettingState {
|
|||||||
gamePath: string;
|
gamePath: string;
|
||||||
gameDir: string;
|
gameDir: string;
|
||||||
serverPath: string;
|
serverPath: string;
|
||||||
|
sdkServerPath: string;
|
||||||
proxyPath: string;
|
proxyPath: string;
|
||||||
serverVersion: string;
|
serverVersion: string;
|
||||||
proxyVersion: string;
|
proxyVersion: string;
|
||||||
|
selectedServer: string;
|
||||||
closingOption: {
|
closingOption: {
|
||||||
isMinimize: boolean;
|
isMinimize: boolean;
|
||||||
isAsk: boolean;
|
isAsk: boolean;
|
||||||
@@ -18,11 +20,13 @@ interface SettingState {
|
|||||||
extraBackgrounds: string[];
|
extraBackgrounds: string[];
|
||||||
setExtraBackgrounds: (newExtraBackgrounds: string[]) => void;
|
setExtraBackgrounds: (newExtraBackgrounds: string[]) => void;
|
||||||
setBackground: (newBackground: string) => void;
|
setBackground: (newBackground: string) => void;
|
||||||
|
setSelectedServer: (newServer: string) => void;
|
||||||
setClosingOption: (newClosingOption: { isMinimize: boolean; isAsk: boolean }) => void;
|
setClosingOption: (newClosingOption: { isMinimize: boolean; isAsk: boolean }) => void;
|
||||||
setLocale: (newLocale: string) => void;
|
setLocale: (newLocale: string) => void;
|
||||||
setGamePath: (newGamePath: string) => void;
|
setGamePath: (newGamePath: string) => void;
|
||||||
setGameDir: (newGameDir: string) => void;
|
setGameDir: (newGameDir: string) => void;
|
||||||
setServerPath: (newServerPath: string) => void;
|
setServerPath: (newServerPath: string) => void;
|
||||||
|
setSdkServerPath: (newSdkServerPath: string) => void;
|
||||||
setProxyPath: (newProxyPath: string) => void;
|
setProxyPath: (newProxyPath: string) => void;
|
||||||
setServerVersion: (newServerVersion: string) => void;
|
setServerVersion: (newServerVersion: string) => void;
|
||||||
setProxyVersion: (newProxyVersion: string) => void;
|
setProxyVersion: (newProxyVersion: string) => void;
|
||||||
@@ -35,22 +39,26 @@ const useSettingStore = create<SettingState>()(
|
|||||||
gamePath: "",
|
gamePath: "",
|
||||||
gameDir: "",
|
gameDir: "",
|
||||||
serverPath: "",
|
serverPath: "",
|
||||||
|
sdkServerPath: "",
|
||||||
proxyPath: "",
|
proxyPath: "",
|
||||||
serverVersion: "",
|
serverVersion: "",
|
||||||
proxyVersion: "",
|
proxyVersion: "",
|
||||||
|
selectedServer: "",
|
||||||
closingOption: {
|
closingOption: {
|
||||||
isMinimize: false,
|
isMinimize: false,
|
||||||
isAsk: true,
|
isAsk: true,
|
||||||
},
|
},
|
||||||
background: "bg-12.jpg",
|
background: "bg-1.jpeg",
|
||||||
extraBackgrounds: [],
|
extraBackgrounds: [],
|
||||||
setExtraBackgrounds: (newExtraBackgrounds: string[]) => set({ extraBackgrounds: newExtraBackgrounds }),
|
setExtraBackgrounds: (newExtraBackgrounds: string[]) => set({ extraBackgrounds: newExtraBackgrounds }),
|
||||||
setBackground: (newBackground: string) => set({ background: newBackground }),
|
setBackground: (newBackground: string) => set({ background: newBackground }),
|
||||||
|
setSelectedServer: (newServer: string) => set({ selectedServer: newServer }),
|
||||||
setClosingOption: (newClosingOption: { isMinimize: boolean; isAsk: boolean }) => set({ closingOption: newClosingOption }),
|
setClosingOption: (newClosingOption: { isMinimize: boolean; isAsk: boolean }) => set({ closingOption: newClosingOption }),
|
||||||
setLocale: (newLocale: string) => set({ locale: newLocale }),
|
setLocale: (newLocale: string) => set({ locale: newLocale }),
|
||||||
setGamePath: (newGamePath: string) => set({ gamePath: newGamePath }),
|
setGamePath: (newGamePath: string) => set({ gamePath: newGamePath }),
|
||||||
setGameDir: (newGameDir: string) => set({ gameDir: newGameDir }),
|
setGameDir: (newGameDir: string) => set({ gameDir: newGameDir }),
|
||||||
setServerPath: (newServerPath: string) => set({ serverPath: newServerPath }),
|
setServerPath: (newServerPath: string) => set({ serverPath: newServerPath }),
|
||||||
|
setSdkServerPath: (newSdkServerPath: string) => set({ sdkServerPath: newSdkServerPath }),
|
||||||
setProxyPath: (newProxyPath: string) => set({ proxyPath: newProxyPath }),
|
setProxyPath: (newProxyPath: string) => set({ proxyPath: newProxyPath }),
|
||||||
setServerVersion: (newServerVersion: string) => set({ serverVersion: newServerVersion }),
|
setServerVersion: (newServerVersion: string) => set({ serverVersion: newServerVersion }),
|
||||||
setProxyVersion: (newProxyVersion: string) => set({ proxyVersion: newProxyVersion }),
|
setProxyVersion: (newProxyVersion: string) => set({ proxyVersion: newProxyVersion }),
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ func (f *FSService) StartWithConsole(path string) (bool, string) {
|
|||||||
base := strings.ToLower(filepath.Base(path))
|
base := strings.ToLower(filepath.Base(path))
|
||||||
if base == "launcher.exe" || base == "starrail.exe" {
|
if base == "launcher.exe" || base == "starrail.exe" {
|
||||||
application.Get().Event.Emit("game:exit")
|
application.Get().Event.Emit("game:exit")
|
||||||
} else if base == "firefly-go_win.exe" || base == "gameserver.exe" {
|
} else if base == "firefly-go_win.exe" || base == "gameserver.exe" || base == "gameserver-go.exe" || base == "server.exe" || base == "sdkserver-go.exe" || base == "sdkserver.exe" {
|
||||||
application.Get().Event.Emit("server:exit")
|
application.Get().Event.Emit("server:exit")
|
||||||
} else if base == "firefly-go-proxy.exe" || base == "proxy.exe" {
|
} else if base == "firefly-go-proxy.exe" || base == "proxy.exe" {
|
||||||
application.Get().Event.Emit("proxy:exit")
|
application.Get().Event.Emit("proxy:exit")
|
||||||
|
|||||||
@@ -40,9 +40,11 @@ func (g *GitService) GetLatestLauncherVersion() (bool, string, string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to Gitea/Forgejo/GitHub Releases API
|
client := &http.Client{Timeout: 10 * time.Second}
|
||||||
|
|
||||||
|
// Fallback to Gitea Releases API
|
||||||
if constant.LauncherGitUrl != "" {
|
if constant.LauncherGitUrl != "" {
|
||||||
resp, err := http.Get(constant.LauncherGitUrl)
|
resp, err := client.Get(constant.LauncherGitUrl)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
body, readErr := io.ReadAll(resp.Body)
|
body, readErr := io.ReadAll(resp.Body)
|
||||||
@@ -55,7 +57,23 @@ func (g *GitService) GetLatestLauncherVersion() (bool, string, string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, "", "no launcher updates found"
|
// Fallback to Gitea Tags API
|
||||||
|
tagsURL := "https://gaytea.cod-algieba.ts.net/api/v1/repos/GaCy/G-Launcher/tags"
|
||||||
|
resp, err := client.Get(tagsURL)
|
||||||
|
if err == nil {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, readErr := io.ReadAll(resp.Body)
|
||||||
|
if readErr == nil {
|
||||||
|
var tags []struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
if json.Unmarshal(body, &tags) == nil && len(tags) > 0 {
|
||||||
|
return true, tags[0].Name, ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, constant.CurrentLauncherVersion, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GitService) UpdateLauncherProgress(version string) (bool, string) {
|
func (g *GitService) UpdateLauncherProgress(version string) (bool, string) {
|
||||||
|
|||||||
@@ -2,26 +2,31 @@ package gitService
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"g-launcher/pkg/constant"
|
"g-launcher/pkg/constant"
|
||||||
"g-launcher/pkg/models"
|
"g-launcher/pkg/models"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v3/pkg/application"
|
"github.com/wailsapp/wails/v3/pkg/application"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (g *GitService) GetLatestServerVersion() (bool, string, string) {
|
func (g *GitService) GetLatestServerVersion() (bool, string, string) {
|
||||||
resp, err := http.Get(constant.ServerGitUrl)
|
client := &http.Client{Timeout: 15 * time.Second}
|
||||||
|
resp, err := client.Get(constant.ServerGitUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "", err.Error()
|
return false, "", err.Error()
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return false, "", err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
var releases []models.ReleaseType
|
var releases []models.ReleaseType
|
||||||
err = json.Unmarshal(body, &releases)
|
err = json.Unmarshal(body, &releases)
|
||||||
@@ -37,35 +42,166 @@ func (g *GitService) GetLatestServerVersion() (bool, string, string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *GitService) DownloadServerProgress(version string) (bool, string) {
|
func (g *GitService) DownloadServerProgress(version string) (bool, string) {
|
||||||
asset, ok := g.getReleaseAsset(version, constant.ServerGitUrl, constant.ServerZipFile)
|
client := &http.Client{Timeout: 15 * time.Second}
|
||||||
if !ok {
|
resp, err := client.Get(constant.ServerGitUrl)
|
||||||
return false, "no release found"
|
if err != nil {
|
||||||
|
return false, fmt.Sprintf("fetch server releases: %v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Sprintf("read server releases: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var releases []*models.ReleaseType
|
||||||
|
if err := json.Unmarshal(body, &releases); err != nil || len(releases) == 0 {
|
||||||
|
return false, "no releases found on server repository"
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetRelease *models.ReleaseType
|
||||||
|
for _, rel := range releases {
|
||||||
|
if rel.TagName == version {
|
||||||
|
targetRelease = rel
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if targetRelease == nil && len(releases) > 0 {
|
||||||
|
targetRelease = releases[0]
|
||||||
|
}
|
||||||
|
if targetRelease == nil {
|
||||||
|
return false, "could not find server release matching version " + version
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(constant.ServerStorageUrl, 0755); err != nil {
|
if err := os.MkdirAll(constant.ServerStorageUrl, 0755); err != nil {
|
||||||
return false, err.Error()
|
return false, err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
saveFile := filepath.Join(constant.ServerStorageUrl, asset.Name)
|
// 1. Search for .zip asset
|
||||||
tmpPath, err := g.downloadFileParallel(saveFile, asset.BrowserDownloadURL, 4, func(percent float64, speed string) {
|
var zipAsset *models.AssetType
|
||||||
|
for _, asset := range targetRelease.Assets {
|
||||||
|
if strings.HasSuffix(strings.ToLower(asset.Name), ".zip") {
|
||||||
|
aCopy := asset
|
||||||
|
zipAsset = &aCopy
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if zipAsset != nil {
|
||||||
|
// Case A: ZIP archive found
|
||||||
|
saveZipPath := filepath.Join(constant.ServerStorageUrl, zipAsset.Name)
|
||||||
|
tmpPath, err := g.downloadFileParallel(saveZipPath, zipAsset.BrowserDownloadURL, 4, func(percent float64, speed string) {
|
||||||
application.Get().Event.Emit("download:server", map[string]interface{}{
|
application.Get().Event.Emit("download:server", map[string]interface{}{
|
||||||
"percent": fmt.Sprintf("%.2f", percent),
|
"percent": fmt.Sprintf("%.2f", percent),
|
||||||
"speed": speed,
|
"speed": speed,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err.Error()
|
return false, fmt.Sprintf("download server zip: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renamed := false
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
if err := os.Rename(tmpPath, saveFile); err == nil {
|
if err := os.Rename(tmpPath, saveZipPath); err == nil {
|
||||||
return true, ""
|
renamed = true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(300 * time.Millisecond)
|
time.Sleep(300 * time.Millisecond)
|
||||||
}
|
}
|
||||||
return false, "failed to rename tmp file after retries"
|
if !renamed {
|
||||||
|
os.Remove(tmpPath)
|
||||||
|
return false, "failed to rename downloaded server zip"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unzip immediately
|
||||||
|
if err := g.unzipParallel(saveZipPath, constant.ServerStorageUrl); err != nil {
|
||||||
|
return false, fmt.Sprintf("unzip server: %v", err)
|
||||||
|
}
|
||||||
|
os.Remove(saveZipPath)
|
||||||
|
return true, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case B: No ZIP archive, download sdkserver and server executables
|
||||||
|
var sdkAsset, serverAsset *models.AssetType
|
||||||
|
for _, asset := range targetRelease.Assets {
|
||||||
|
nameLower := strings.ToLower(asset.Name)
|
||||||
|
if strings.Contains(nameLower, "sdkserver") {
|
||||||
|
aCopy := asset
|
||||||
|
sdkAsset = &aCopy
|
||||||
|
} else if strings.Contains(nameLower, "server") {
|
||||||
|
aCopy := asset
|
||||||
|
serverAsset = &aCopy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sdkAsset == nil && serverAsset == nil {
|
||||||
|
return false, "no zip or server executable assets found in release"
|
||||||
|
}
|
||||||
|
|
||||||
|
if sdkAsset != nil {
|
||||||
|
saveSdk := filepath.Join(constant.ServerStorageUrl, sdkAsset.Name)
|
||||||
|
tmpPath, err := g.downloadFileParallel(saveSdk, sdkAsset.BrowserDownloadURL, 4, func(percent float64, speed string) {
|
||||||
|
application.Get().Event.Emit("download:server", map[string]interface{}{
|
||||||
|
"percent": fmt.Sprintf("%.2f", percent*0.5),
|
||||||
|
"speed": speed,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
_ = os.Rename(tmpPath, saveSdk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if serverAsset != nil {
|
||||||
|
saveServer := filepath.Join(constant.ServerStorageUrl, serverAsset.Name)
|
||||||
|
tmpPath, err := g.downloadFileParallel(saveServer, serverAsset.BrowserDownloadURL, 4, func(percent float64, speed string) {
|
||||||
|
application.Get().Event.Emit("download:server", map[string]interface{}{
|
||||||
|
"percent": fmt.Sprintf("%.2f", 50.0+percent*0.5),
|
||||||
|
"speed": speed,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
_ = os.Rename(tmpPath, saveServer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GitService) UnzipServer() {
|
func (g *GitService) UnzipServer() {
|
||||||
g.unzipParallel(filepath.Join(constant.ServerStorageUrl, constant.ServerZipFile), constant.ServerStorageUrl)
|
entries, err := os.ReadDir(constant.ServerStorageUrl)
|
||||||
os.Remove(filepath.Join(constant.ServerStorageUrl, constant.ServerZipFile))
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, entry := range entries {
|
||||||
|
if !entry.IsDir() && strings.HasSuffix(strings.ToLower(entry.Name()), ".zip") {
|
||||||
|
zipPath := filepath.Join(constant.ServerStorageUrl, entry.Name())
|
||||||
|
_ = g.unzipParallel(zipPath, constant.ServerStorageUrl)
|
||||||
|
_ = os.Remove(zipPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GitService) FindServerExecutables() (string, string) {
|
||||||
|
serverDir := constant.ServerStorageUrl
|
||||||
|
var gameServer, sdkServer string
|
||||||
|
|
||||||
|
// Candidate filenames for game server
|
||||||
|
for _, name := range []string{"gameserver-go.exe", "server.exe", "gameserver.exe", "firefly-go_win.exe"} {
|
||||||
|
p := filepath.Join(serverDir, name)
|
||||||
|
if info, err := os.Stat(p); err == nil && !info.IsDir() {
|
||||||
|
gameServer = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Candidate filenames for sdk server
|
||||||
|
for _, name := range []string{"sdkserver-go.exe", "sdkserver.exe"} {
|
||||||
|
p := filepath.Join(serverDir, name)
|
||||||
|
if info, err := os.Stat(p); err == nil && !info.IsDir() {
|
||||||
|
sdkServer = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gameServer, sdkServer
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package constant
|
package constant
|
||||||
|
|
||||||
const ProxyGitUrl = "https://git.kain.io.vn/api/v1/repos/Firefly-Shelter/FireflyGo_Proxy/releases"
|
const ProxyGitUrl = "https://git.kain.io.vn/api/v1/repos/Firefly-Shelter/FireflyGo_Proxy/releases"
|
||||||
const ServerGitUrl = "https://git.kain.io.vn/api/v1/repos/Firefly-Shelter/FireflyGo_Local_Archive/releases"
|
const ServerGitUrl = "https://gaytea.cod-algieba.ts.net/api/v1/repos/GaCySR/GaCy-GO/releases"
|
||||||
const LauncherGitUrl = "https://gaytea.cod-algieba.ts.net/api/v1/repos/GaCy/G-Launcher/releases"
|
const LauncherGitUrl = "https://gaytea.cod-algieba.ts.net/api/v1/repos/GaCy/G-Launcher/releases"
|
||||||
const LauncherManifestURL = "https://gaytea.cod-algieba.ts.net/GaCy/G-Launcher/releases/download/latest/latest.json"
|
const LauncherManifestURL = "https://gaytea.cod-algieba.ts.net/GaCy/G-Launcher/releases/download/latest/latest.json"
|
||||||
const LauncherDownloadURL = "https://gaytea.cod-algieba.ts.net/GaCy/G-Launcher/releases/download/latest/G-Launcher.exe"
|
const LauncherDownloadURL = "https://gaytea.cod-algieba.ts.net/GaCy/G-Launcher/releases/download/latest/G-Launcher.exe"
|
||||||
@@ -11,7 +11,7 @@ const LauncherBuildTempDir = "temp/updater_build"
|
|||||||
|
|
||||||
const ServerStorageUrl = "./server"
|
const ServerStorageUrl = "./server"
|
||||||
const ProxyStorageUrl = "./proxy"
|
const ProxyStorageUrl = "./proxy"
|
||||||
const ServerZipFile = "prebuild_win_x86.zip"
|
const ServerZipFile = "gacy 4.6.54.zip"
|
||||||
const ProxyFile = "firefly-go-proxy.exe"
|
const ProxyFile = "firefly-go-proxy.exe"
|
||||||
const LauncherFile = "G-Launcher.exe"
|
const LauncherFile = "G-Launcher.exe"
|
||||||
const TempUrl = "./temp"
|
const TempUrl = "./temp"
|
||||||
|
|||||||