<# .SYNOPSIS RR3 Asset Downloader - Downloads game assets from EA's CDN while available .DESCRIPTION Parses asset manifests and downloads files from EA's servers. Verifies MD5 hashes and organizes files for community server. .PARAMETER ManifestFiles Specific manifest files to process (default: critical assets only) .PARAMETER MaxParallelDownloads Maximum concurrent downloads (default: 5) .PARAMETER TestMode Download first 10 assets only for testing #> param( [string[]]$ManifestFiles = @( "asset_list_base.txt", "asset_list_audio_base.txt", "asset_list_base_gui.txt" ), [int]$MaxParallelDownloads = 5, [switch]$TestMode ) $ErrorActionPreference = "Continue" # Configuration $ManifestPath = "E:\rr3\RR3CommunityServer\RR3CommunityServer\Assets\manifests" $DestinationPath = "E:\rr3\RR3CommunityServer\RR3CommunityServer\Assets\downloaded" $EaCdnBaseUrl = "https://d1q35ni3zsr8wd.cloudfront.net" # EA's actual CDN (CloudFront) $LogFile = "E:\rr3\asset-download-log.txt" # Statistics $Global:Stats = @{ Total = 0 Downloaded = 0 Skipped = 0 Failed = 0 BytesDownloaded = 0 } # Initialize Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host " 🎮 Real Racing 3 - Asset Preservation Downloader 💾" -ForegroundColor Cyan Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host "" if (!(Test-Path $DestinationPath)) { New-Item -ItemType Directory -Path $DestinationPath | Out-Null Write-Host "✓ Created download directory" -ForegroundColor Green } # Ensure log directory exists $LogDir = Split-Path $LogFile -Parent if (!(Test-Path $LogDir)) { New-Item -ItemType Directory -Path $LogDir | Out-Null } "=== RR3 Asset Download Started: $(Get-Date) ===" | Out-File $LogFile -Encoding utf8 function Get-MD5Hash { param([string]$FilePath) $md5 = [System.Security.Cryptography.MD5]::Create() $stream = [System.IO.File]::OpenRead($FilePath) $hash = $md5.ComputeHash($stream) $stream.Close() return [BitConverter]::ToString($hash).Replace("-", "").ToLower() } function Download-Asset { param( [string]$AssetPath, [string]$ExpectedMD5, [int]$CompressedSize, [int]$UncompressedSize ) try { # Determine local save path $relativePath = $AssetPath.TrimStart('/') $localPath = Join-Path $DestinationPath $relativePath $localDir = Split-Path $localPath -Parent # Skip if already downloaded and hash matches if (Test-Path $localPath) { $actualMD5 = Get-MD5Hash $localPath if ($actualMD5 -eq $ExpectedMD5) { Write-Host " ⏭️ SKIP: $AssetPath (already cached)" -ForegroundColor Gray $Global:Stats.Skipped++ return $true } else { Write-Host " 🔄 RE-DOWNLOAD: $AssetPath (hash mismatch)" -ForegroundColor Yellow } } # Ensure directory exists if (!(Test-Path $localDir)) { New-Item -ItemType Directory -Path $localDir -Force | Out-Null } # Download from EA CDN $url = "$EaCdnBaseUrl$AssetPath" Write-Host " ⬇️ Downloading: $AssetPath ($([math]::Round($CompressedSize/1KB, 2)) KB)" -ForegroundColor Cyan $webClient = New-Object System.Net.WebClient $webClient.Headers.Add("User-Agent", "RealRacing3/12.6.0") $webClient.DownloadFile($url, $localPath) $webClient.Dispose() # Verify MD5 $actualMD5 = Get-MD5Hash $localPath if ($actualMD5 -eq $ExpectedMD5) { Write-Host " ✅ SUCCESS: $AssetPath" -ForegroundColor Green $Global:Stats.Downloaded++ $Global:Stats.BytesDownloaded += (Get-Item $localPath).Length "SUCCESS: $AssetPath" | Out-File $LogFile -Append -Encoding utf8 return $true } else { Write-Host " ❌ HASH MISMATCH: $AssetPath" -ForegroundColor Red Write-Host " Expected: $ExpectedMD5" -ForegroundColor Red Write-Host " Got: $actualMD5" -ForegroundColor Red Remove-Item $localPath -Force $Global:Stats.Failed++ "FAILED (hash): $AssetPath" | Out-File $LogFile -Append -Encoding utf8 return $false } } catch { Write-Host " ❌ DOWNLOAD ERROR: $AssetPath" -ForegroundColor Red Write-Host " Error: $($_.Exception.Message)" -ForegroundColor Red $Global:Stats.Failed++ "FAILED (error): $AssetPath - $($_.Exception.Message)" | Out-File $LogFile -Append -Encoding utf8 return $false } } # Process each manifest foreach ($manifestFile in $ManifestFiles) { $manifestPath = Join-Path $ManifestPath $manifestFile if (!(Test-Path $manifestPath)) { Write-Host "⚠️ Manifest not found: $manifestFile" -ForegroundColor Yellow continue } Write-Host "" Write-Host "📋 Processing: $manifestFile" -ForegroundColor Cyan Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan $lines = Get-Content $manifestPath if ($TestMode) { Write-Host "🧪 TEST MODE: Downloading first 10 assets only" -ForegroundColor Yellow $lines = $lines | Select-Object -First 10 } $Global:Stats.Total += $lines.Count # Download assets $index = 0 foreach ($line in $lines) { $index++ $parts = $line -split "`t" if ($parts.Count -ne 4) { Write-Host " ⚠️ Invalid line format: $line" -ForegroundColor Yellow continue } $assetPath = $parts[0] $md5 = $parts[1] $compressedSize = [int]$parts[2] $uncompressedSize = [int]$parts[3] Write-Host "" Write-Host "[$index/$($lines.Count)] Asset: $assetPath" -ForegroundColor White Download-Asset -AssetPath $assetPath -ExpectedMD5 $md5 -CompressedSize $compressedSize -UncompressedSize $uncompressedSize # Respectful delay (don't hammer EA's servers) Start-Sleep -Milliseconds 500 } } # Summary Write-Host "" Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host " 📊 DOWNLOAD SUMMARY" -ForegroundColor Cyan Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host "" Write-Host "Total Assets: $($Global:Stats.Total)" -ForegroundColor White Write-Host "Downloaded: $($Global:Stats.Downloaded)" -ForegroundColor Green Write-Host "Skipped (cached): $($Global:Stats.Skipped)" -ForegroundColor Gray Write-Host "Failed: $($Global:Stats.Failed)" -ForegroundColor Red Write-Host "Data Downloaded: $([math]::Round($Global:Stats.BytesDownloaded/1MB, 2)) MB" -ForegroundColor Cyan Write-Host "" if ($Global:Stats.Failed -gt 0) { Write-Host "⚠️ Some downloads failed. Check log: $LogFile" -ForegroundColor Yellow } else { Write-Host "✅ All downloads completed successfully!" -ForegroundColor Green } Write-Host "" Write-Host "Log saved to: $LogFile" -ForegroundColor Gray Write-Host "Assets saved to: $DestinationPath" -ForegroundColor Gray "=== Download Completed: $(Get-Date) ===" | Out-File $LogFile -Append -Encoding utf8 "Total: $($Global:Stats.Total), Downloaded: $($Global:Stats.Downloaded), Skipped: $($Global:Stats.Skipped), Failed: $($Global:Stats.Failed)" | Out-File $LogFile -Append -Encoding utf8