mirror of
https://git.sanhost.net/sanasol/hytale-f2p
synced 2026-02-26 11:41:49 -03:00
Compare commits
3 Commits
e7a033932f
...
v2.3.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8435fc698c | ||
|
|
6c369edb0f | ||
|
|
fdd8e59ec4 |
@@ -439,7 +439,7 @@ exec "$REAL_JAVA" "\${ARGS[@]}"
|
||||
// This enables runtime auth patching without modifying the server JAR
|
||||
const agentJar = path.join(gameLatest, 'Server', 'dualauth-agent.jar');
|
||||
if (fs.existsSync(agentJar)) {
|
||||
const agentFlag = `-javaagent:${agentJar}`;
|
||||
const agentFlag = `-javaagent:"${agentJar}"`;
|
||||
env.JAVA_TOOL_OPTIONS = env.JAVA_TOOL_OPTIONS
|
||||
? `${env.JAVA_TOOL_OPTIONS} ${agentFlag}`
|
||||
: agentFlag;
|
||||
|
||||
@@ -85,8 +85,9 @@ async function downloadPWR(branch = 'release', fileName = 'v8', progressCallback
|
||||
console.log(`[DownloadPWR] Mirror URL: ${url}`);
|
||||
} catch (error) {
|
||||
console.error(`[DownloadPWR] Failed to get mirror URL: ${error.message}`);
|
||||
const { MIRROR_BASE_URL } = require('../services/versionManager');
|
||||
url = `${MIRROR_BASE_URL}/${osName}/${arch}/${branch}/0_to_${extractVersionNumber(fileName)}.pwr`;
|
||||
const { getPatchesBaseUrl } = require('../services/versionManager');
|
||||
const baseUrl = await getPatchesBaseUrl();
|
||||
url = `${baseUrl}/${osName}/${arch}/${branch}/0_to_${extractVersionNumber(fileName)}.pwr`;
|
||||
console.log(`[DownloadPWR] Fallback URL: ${url}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,20 +3,56 @@ const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
const { getOS, getArch } = require('../utils/platformUtils');
|
||||
|
||||
// Patches CDN via auth server redirect gateway (allows instant CDN switching)
|
||||
// Patches base URL fetched dynamically from auth server
|
||||
const AUTH_DOMAIN = process.env.HYTALE_AUTH_DOMAIN || 'auth.sanasol.ws';
|
||||
const MIRROR_BASE_URL = `https://${AUTH_DOMAIN}/patches`;
|
||||
const MIRROR_MANIFEST_URL = `${MIRROR_BASE_URL}/manifest.json`;
|
||||
const PATCHES_CONFIG_URL = `https://${AUTH_DOMAIN}/api/patches-config`;
|
||||
|
||||
// Fallback: latest known build number if manifest is unreachable
|
||||
const FALLBACK_LATEST_BUILD = 11;
|
||||
|
||||
let patchesBaseUrl = null;
|
||||
let patchesConfigTime = 0;
|
||||
const PATCHES_CONFIG_CACHE_DURATION = 300000; // 5 minutes
|
||||
|
||||
let manifestCache = null;
|
||||
let manifestCacheTime = 0;
|
||||
const MANIFEST_CACHE_DURATION = 60000; // 1 minute
|
||||
|
||||
/**
|
||||
* Fetch the mirror manifest from MEGA S4
|
||||
* Fetch patches base URL from auth server config endpoint
|
||||
*/
|
||||
async function getPatchesBaseUrl() {
|
||||
const now = Date.now();
|
||||
if (patchesBaseUrl && (now - patchesConfigTime) < PATCHES_CONFIG_CACHE_DURATION) {
|
||||
return patchesBaseUrl;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('[Mirror] Fetching patches config from:', PATCHES_CONFIG_URL);
|
||||
const response = await axios.get(PATCHES_CONFIG_URL, {
|
||||
timeout: 10000,
|
||||
headers: { 'User-Agent': 'Hytale-F2P-Launcher' }
|
||||
});
|
||||
|
||||
if (response.data && response.data.patches_url) {
|
||||
patchesBaseUrl = response.data.patches_url.replace(/\/+$/, '');
|
||||
patchesConfigTime = now;
|
||||
console.log('[Mirror] Patches base URL:', patchesBaseUrl);
|
||||
return patchesBaseUrl;
|
||||
}
|
||||
throw new Error('Invalid patches config');
|
||||
} catch (error) {
|
||||
console.error('[Mirror] Error fetching patches config:', error.message);
|
||||
if (patchesBaseUrl) {
|
||||
console.log('[Mirror] Using cached patches URL:', patchesBaseUrl);
|
||||
return patchesBaseUrl;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the mirror manifest
|
||||
*/
|
||||
async function fetchMirrorManifest() {
|
||||
const now = Date.now();
|
||||
@@ -26,9 +62,12 @@ async function fetchMirrorManifest() {
|
||||
return manifestCache;
|
||||
}
|
||||
|
||||
const baseUrl = await getPatchesBaseUrl();
|
||||
const manifestUrl = `${baseUrl}/manifest.json`;
|
||||
|
||||
try {
|
||||
console.log('[Mirror] Fetching manifest from:', MIRROR_MANIFEST_URL);
|
||||
const response = await axios.get(MIRROR_MANIFEST_URL, {
|
||||
console.log('[Mirror] Fetching manifest from:', manifestUrl);
|
||||
const response = await axios.get(manifestUrl, {
|
||||
timeout: 15000,
|
||||
headers: { 'User-Agent': 'Hytale-F2P-Launcher' }
|
||||
});
|
||||
@@ -82,9 +121,10 @@ function getPlatformPatches(manifest, branch = 'release') {
|
||||
* Find optimal patch path using BFS with download size minimization
|
||||
* Returns array of { from, to, url, size, key } steps, or null if no path found
|
||||
*/
|
||||
function findOptimalPatchPath(currentBuild, targetBuild, patches) {
|
||||
async function findOptimalPatchPath(currentBuild, targetBuild, patches) {
|
||||
if (currentBuild >= targetBuild) return [];
|
||||
|
||||
const baseUrl = await getPatchesBaseUrl();
|
||||
const edges = {};
|
||||
for (const patch of patches) {
|
||||
if (!edges[patch.from]) edges[patch.from] = [];
|
||||
@@ -118,7 +158,7 @@ function findOptimalPatchPath(currentBuild, targetBuild, patches) {
|
||||
path: [...path, {
|
||||
from: edge.from,
|
||||
to: edge.to,
|
||||
url: `${MIRROR_BASE_URL}/${edge.key}`,
|
||||
url: `${baseUrl}/${edge.key}`,
|
||||
size: edge.size,
|
||||
key: edge.key
|
||||
}],
|
||||
@@ -139,7 +179,7 @@ async function getUpdatePlan(currentBuild, targetBuild, branch = 'release') {
|
||||
const patches = getPlatformPatches(manifest, branch);
|
||||
|
||||
// Try optimal path
|
||||
const steps = findOptimalPatchPath(currentBuild, targetBuild, patches);
|
||||
const steps = await findOptimalPatchPath(currentBuild, targetBuild, patches);
|
||||
|
||||
if (steps && steps.length > 0) {
|
||||
const totalSize = steps.reduce((sum, s) => sum + s.size, 0);
|
||||
@@ -150,10 +190,11 @@ async function getUpdatePlan(currentBuild, targetBuild, branch = 'release') {
|
||||
// Fallback: full install 0 -> target
|
||||
const fullPatch = patches.find(p => p.from === 0 && p.to === targetBuild);
|
||||
if (fullPatch) {
|
||||
const baseUrl = await getPatchesBaseUrl();
|
||||
const step = {
|
||||
from: 0,
|
||||
to: targetBuild,
|
||||
url: `${MIRROR_BASE_URL}/${fullPatch.key}`,
|
||||
url: `${baseUrl}/${fullPatch.key}`,
|
||||
size: fullPatch.size,
|
||||
key: fullPatch.key
|
||||
};
|
||||
@@ -200,7 +241,8 @@ async function getPWRUrl(branch = 'release', version = 'v11') {
|
||||
const fullPatch = patches.find(p => p.from === 0 && p.to === targetBuild);
|
||||
|
||||
if (fullPatch) {
|
||||
const url = `${MIRROR_BASE_URL}/${fullPatch.key}`;
|
||||
const baseUrl = await getPatchesBaseUrl();
|
||||
const url = `${baseUrl}/${fullPatch.key}`;
|
||||
console.log(`[Mirror] PWR URL: ${url}`);
|
||||
return url;
|
||||
}
|
||||
@@ -216,7 +258,8 @@ async function getPWRUrl(branch = 'release', version = 'v11') {
|
||||
}
|
||||
|
||||
// Construct mirror URL (will work if patch was uploaded but manifest is stale)
|
||||
return `${MIRROR_BASE_URL}/${os}/${arch}/${branch}/0_to_${targetBuild}.pwr`;
|
||||
const baseUrl = await getPatchesBaseUrl();
|
||||
return `${baseUrl}/${os}/${arch}/${branch}/0_to_${targetBuild}.pwr`;
|
||||
}
|
||||
|
||||
// Backward-compatible alias
|
||||
@@ -240,14 +283,15 @@ function extractVersionNumber(version) {
|
||||
return isNaN(num) ? 0 : num;
|
||||
}
|
||||
|
||||
function buildArchiveUrl(buildNumber, branch = 'release') {
|
||||
async function buildArchiveUrl(buildNumber, branch = 'release') {
|
||||
const baseUrl = await getPatchesBaseUrl();
|
||||
const os = getOS();
|
||||
const arch = getArch();
|
||||
return `${MIRROR_BASE_URL}/${os}/${arch}/${branch}/0_to_${buildNumber}.pwr`;
|
||||
return `${baseUrl}/${os}/${arch}/${branch}/0_to_${buildNumber}.pwr`;
|
||||
}
|
||||
|
||||
async function checkArchiveExists(buildNumber, branch = 'release') {
|
||||
const url = buildArchiveUrl(buildNumber, branch);
|
||||
const url = await buildArchiveUrl(buildNumber, branch);
|
||||
try {
|
||||
const response = await axios.head(url, { timeout: 10000 });
|
||||
return response.status === 200;
|
||||
@@ -269,7 +313,7 @@ async function discoverAvailableVersions(latestKnown, branch = 'release') {
|
||||
|
||||
async function extractVersionDetails(targetVersion, branch = 'release') {
|
||||
const buildNumber = extractVersionNumber(targetVersion);
|
||||
const fullUrl = buildArchiveUrl(buildNumber, branch);
|
||||
const fullUrl = await buildArchiveUrl(buildNumber, branch);
|
||||
|
||||
return {
|
||||
version: targetVersion,
|
||||
@@ -340,5 +384,5 @@ module.exports = {
|
||||
extractVersionNumber,
|
||||
getPlatformPatches,
|
||||
findOptimalPatchPath,
|
||||
MIRROR_BASE_URL
|
||||
getPatchesBaseUrl
|
||||
};
|
||||
|
||||
8
main.js
8
main.js
@@ -84,8 +84,8 @@ function setDiscordActivity() {
|
||||
largeImageText: 'Hytale F2P Launcher',
|
||||
buttons: [
|
||||
{
|
||||
label: 'GitHub',
|
||||
url: 'https://github.com/amiayweb/Hytale-F2P'
|
||||
label: 'Download',
|
||||
url: 'https://git.sanhost.net/sanasol/hytale-f2p/releases'
|
||||
},
|
||||
{
|
||||
label: 'Discord',
|
||||
@@ -964,8 +964,8 @@ ipcMain.handle('open-external', async (event, url) => {
|
||||
|
||||
ipcMain.handle('open-download-page', async () => {
|
||||
try {
|
||||
// Open GitHub releases page for manual download
|
||||
await shell.openExternal('https://github.com/amiayweb/Hytale-F2P/releases/latest');
|
||||
// Open Forgejo releases page for manual download
|
||||
await shell.openExternal('https://git.sanhost.net/sanasol/hytale-f2p/releases/latest');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Failed to open download page:', error);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "hytale-f2p-launcher",
|
||||
"version": "2.3.2",
|
||||
"version": "2.3.4",
|
||||
"description": "A modern, cross-platform launcher for Hytale with automatic updates and multi-client support",
|
||||
"homepage": "https://github.com/amiayweb/Hytale-F2P",
|
||||
"homepage": "https://git.sanhost.net/sanasol/hytale-f2p",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"start": "electron .",
|
||||
|
||||
Reference in New Issue
Block a user