Use new version API and default to v8 PWR

This commit is contained in:
AMIAY
2026-02-11 10:43:18 +01:00
parent bcc7476322
commit 4502c11bd0
4 changed files with 203 additions and 30 deletions

View File

@@ -1,5 +1,5 @@
const FORCE_CLEAN_INSTALL_VERSION = false;
const CLEAN_INSTALL_TEST_VERSION = '4.pwr';
const CLEAN_INSTALL_TEST_VERSION = 'v4';
module.exports = {
FORCE_CLEAN_INSTALL_VERSION,

View File

@@ -64,7 +64,7 @@ async function safeRemoveDirectory(dirPath, maxRetries = 3) {
}
}
async function downloadPWR(branch = 'release', fileName = '7.pwr', progressCallback, cacheDir = CACHE_DIR, manualRetry = false) {
async function downloadPWR(branch = 'release', fileName = 'v8', progressCallback, cacheDir = CACHE_DIR, manualRetry = false) {
const osName = getOS();
const arch = getArch();
@@ -72,8 +72,23 @@ async function downloadPWR(branch = 'release', fileName = '7.pwr', progressCallb
throw new Error('Hytale x86_64 Intel Mac Support has not been released yet. Please check back later.');
}
const url = `https://game-patches.hytale.com/patches/${osName}/${arch}/${branch}/0/${fileName}`;
const dest = path.join(cacheDir, `${branch}_${fileName}`);
const { getPWRUrlFromNewAPI } = require('../services/versionManager');
let url;
let isUsingNewAPI = false;
try {
console.log(`[DownloadPWR] Fetching URL from new API for branch: ${branch}, version: ${fileName}`);
url = await getPWRUrlFromNewAPI(branch, fileName);
isUsingNewAPI = true;
console.log(`[DownloadPWR] Using new API URL: ${url}`);
} catch (error) {
console.error(`[DownloadPWR] Failed to get URL from new API: ${error.message}`);
console.log(`[DownloadPWR] Falling back to old URL format`);
url = `https://game-patches.hytale.com/patches/${osName}/${arch}/${branch}/0/${fileName}.pwr`;
}
const dest = path.join(cacheDir, `${branch}_${fileName}.pwr`);
// Check if file exists and validate it
if (fs.existsSync(dest) && !manualRetry) {
@@ -93,7 +108,7 @@ async function downloadPWR(branch = 'release', fileName = '7.pwr', progressCallb
}
}
console.log('Fetching PWR patch file:', url);
console.log(`Fetching PWR patch file from ${isUsingNewAPI ? 'NEW API' : 'old API'}:`, url);
try {
if (manualRetry) {

View File

@@ -6,10 +6,141 @@ const { smartRequest } = require('../utils/proxyClient');
const BASE_PATCH_URL = 'https://game-patches.hytale.com/patches';
const MANIFEST_API = 'https://files.hytalef2p.com/api/patch_manifest';
const NEW_API_URL = 'https://thecute.cloud/ShipOfYarn/api.php';
let apiCache = null;
let apiCacheTime = 0;
const API_CACHE_DURATION = 60000; // 1 minute
async function fetchNewAPI() {
const now = Date.now();
if (apiCache && (now - apiCacheTime) < API_CACHE_DURATION) {
console.log('[NewAPI] Using cached API data');
return apiCache;
}
try {
console.log('[NewAPI] Fetching from:', NEW_API_URL);
const response = await axios.get(NEW_API_URL, {
timeout: 15000,
headers: {
'User-Agent': 'Hytale-F2P-Launcher'
}
});
if (response.data && response.data.hytale) {
apiCache = response.data;
apiCacheTime = now;
console.log('[NewAPI] API data fetched and cached successfully');
return response.data;
} else {
throw new Error('Invalid API response structure');
}
} catch (error) {
console.error('[NewAPI] Error fetching API:', error.message);
if (apiCache) {
console.log('[NewAPI] Using expired cache due to error');
return apiCache;
}
throw error;
}
}
async function getLatestVersionFromNewAPI(branch = 'release') {
try {
const apiData = await fetchNewAPI();
const osName = getOS();
const arch = getArch();
let osKey = osName;
if (osName === 'darwin') {
osKey = 'mac';
}
const branchData = apiData.hytale[branch];
if (!branchData || !branchData[osKey]) {
throw new Error(`No data found for branch: ${branch}, OS: ${osKey}`);
}
const osData = branchData[osKey];
const versions = Object.keys(osData).filter(key => key.endsWith('.pwr'));
if (versions.length === 0) {
throw new Error(`No .pwr files found for ${osKey}`);
}
const versionNumbers = versions.map(v => {
const match = v.match(/v(\d+)/);
return match ? parseInt(match[1]) : 0;
});
const latestVersionNumber = Math.max(...versionNumbers);
console.log(`[NewAPI] Latest version number: ${latestVersionNumber} for branch ${branch}`);
return `v${latestVersionNumber}`;
} catch (error) {
console.error('[NewAPI] Error getting latest version:', error.message);
throw error;
}
}
async function getPWRUrlFromNewAPI(branch = 'release', version = 'v8') {
try {
const apiData = await fetchNewAPI();
const osName = getOS();
const arch = getArch();
let osKey = osName;
if (osName === 'darwin') {
osKey = 'mac';
}
let fileName;
if (osName === 'windows') {
fileName = `${version}-windows-amd64.pwr`;
} else if (osName === 'linux') {
fileName = `${version}-linux-amd64.pwr`;
} else if (osName === 'darwin') {
fileName = `${version}-darwin-arm64.pwr`;
}
const branchData = apiData.hytale[branch];
if (!branchData || !branchData[osKey]) {
throw new Error(`No data found for branch: ${branch}, OS: ${osKey}`);
}
const osData = branchData[osKey];
const url = osData[fileName];
if (!url) {
throw new Error(`No URL found for ${fileName}`);
}
console.log(`[NewAPI] URL for ${fileName}: ${url}`);
return url;
} catch (error) {
console.error('[NewAPI] Error getting PWR URL:', error.message);
throw error;
}
}
async function getLatestClientVersion(branch = 'release') {
try {
console.log(`Fetching latest client version from API (branch: ${branch})...`);
console.log(`[NewAPI] Fetching latest client version from new API (branch: ${branch})...`);
// Utiliser la nouvelle API
const latestVersion = await getLatestVersionFromNewAPI(branch);
console.log(`[NewAPI] Latest client version for ${branch}: ${latestVersion}`);
return latestVersion;
} catch (error) {
console.error('[NewAPI] Error fetching client version from new API:', error.message);
console.log('[NewAPI] Falling back to old API...');
// Fallback vers l'ancienne API si la nouvelle échoue
try {
const response = await smartRequest(`https://files.hytalef2p.com/api/version_client?branch=${branch}`, {
timeout: 40000,
headers: {
@@ -19,18 +150,41 @@ async function getLatestClientVersion(branch = 'release') {
if (response.data && response.data.client_version) {
const version = response.data.client_version;
console.log(`Latest client version for ${branch}: ${version}`);
console.log(`Latest client version for ${branch} (old API): ${version}`);
return version;
} else {
console.log('Warning: Invalid API response, falling back to latest known version (7.pwr)');
return '7.pwr';
console.log('Warning: Invalid API response, falling back to latest known version (v8)');
return 'v8';
}
} catch (error) {
console.error('Error fetching client version:', error.message);
console.log('Warning: API unavailable, falling back to latest known version (7.pwr)');
return '7.pwr';
} catch (fallbackError) {
console.error('Error fetching client version from old API:', fallbackError.message);
console.log('Warning: Both APIs unavailable, falling back to latest known version (v8)');
return 'v8';
}
}
}
// Fonction utilitaire pour extraire le numéro de version
// Supporte les formats: "7.pwr", "v8", "v8-windows-amd64.pwr", etc.
function extractVersionNumber(version) {
if (!version) return 0;
// Nouveau format: "v8" ou "v8-xxx.pwr"
const vMatch = version.match(/v(\d+)/);
if (vMatch) {
return parseInt(vMatch[1]);
}
// Ancien format: "7.pwr"
const pwrMatch = version.match(/(\d+)\.pwr/);
if (pwrMatch) {
return parseInt(pwrMatch[1]);
}
// Fallback: essayer de parser directement
const num = parseInt(version);
return isNaN(num) ? 0 : num;
}
function buildArchiveUrl(buildNumber, branch = 'release') {
const os = getOS();
@@ -50,7 +204,7 @@ async function checkArchiveExists(buildNumber, branch = 'release') {
async function discoverAvailableVersions(latestKnown, branch = 'release', maxProbe = 50) {
const available = [];
const latest = parseInt(latestKnown.replace('.pwr', ''));
const latest = extractVersionNumber(latestKnown);
for (let i = latest; i >= Math.max(1, latest - maxProbe); i--) {
const exists = await checkArchiveExists(i, branch);
@@ -77,7 +231,7 @@ async function fetchPatchManifest(branch = 'release') {
}
async function extractVersionDetails(targetVersion, branch = 'release') {
const buildNumber = parseInt(targetVersion.replace('.pwr', ''));
const buildNumber = extractVersionNumber(targetVersion);
const previousBuild = buildNumber - 1;
const manifest = await fetchPatchManifest(branch);
@@ -103,8 +257,8 @@ function canUseDifferentialUpdate(currentVersion, targetDetails) {
if (!currentVersion) return false;
const currentBuild = parseInt(currentVersion.replace('.pwr', ''));
const expectedSource = parseInt(targetDetails.sourceVersion?.replace('.pwr', '') || '0');
const currentBuild = extractVersionNumber(currentVersion);
const expectedSource = extractVersionNumber(targetDetails.sourceVersion);
return currentBuild === expectedSource;
}
@@ -112,8 +266,8 @@ function canUseDifferentialUpdate(currentVersion, targetDetails) {
function needsIntermediatePatches(currentVersion, targetVersion) {
if (!currentVersion) return [];
const current = parseInt(currentVersion.replace('.pwr', ''));
const target = parseInt(targetVersion.replace('.pwr', ''));
const current = extractVersionNumber(currentVersion);
const target = extractVersionNumber(targetVersion);
const intermediates = [];
for (let i = current + 1; i <= target; i++) {
@@ -160,5 +314,9 @@ module.exports = {
needsIntermediatePatches,
computeFileChecksum,
validateChecksum,
getInstalledClientVersion
getInstalledClientVersion,
fetchNewAPI,
getLatestVersionFromNewAPI,
getPWRUrlFromNewAPI,
extractVersionNumber
};

View File

@@ -627,7 +627,7 @@ ipcMain.handle('install-game', async (event, playerName, javaPath, installPath,
console.log('[Main] Processing Butler error with retry context');
errorData.retryData = {
branch: error.branch || 'release',
fileName: error.fileName || '7.pwr',
fileName: error.fileName || 'v8',
cacheDir: error.cacheDir
};
errorData.canRetry = error.canRetry !== false;
@@ -647,7 +647,7 @@ ipcMain.handle('install-game', async (event, playerName, javaPath, installPath,
console.log('[Main] Processing generic error, creating default retry data');
errorData.retryData = {
branch: 'release',
fileName: '7.pwr'
fileName: 'v8'
};
// For generic errors, assume it's retryable unless specified
errorData.canRetry = error.canRetry !== false;
@@ -887,7 +887,7 @@ ipcMain.handle('retry-download', async (event, retryData) => {
console.log('[IPC] Invalid retry data, using PWR defaults');
retryData = {
branch: 'release',
fileName: '7.pwr'
fileName: 'v8'
};
}
@@ -921,7 +921,7 @@ ipcMain.handle('retry-download', async (event, retryData) => {
} :
{
branch: retryData?.branch || 'release',
fileName: retryData?.fileName || '7.pwr',
fileName: retryData?.fileName || 'v8',
cacheDir: retryData?.cacheDir
};