#Requires -Version 5.1 # AmericanKey - Script Unificado # Combina fix-st e SteamDowngrader # Limpar tela Clear-Host # Cabeçalho Write-Host "" Write-Host "===============================================================" -ForegroundColor DarkYellow Write-Host "AmericanKey - Script Unificado - por discord.gg/americankey" -ForegroundColor Cyan Write-Host "===============================================================" -ForegroundColor DarkYellow Write-Host "" # Garantir que o diretório temp existe if (-not $env:TEMP -or -not (Test-Path $env:TEMP)) { if ($env:LOCALAPPDATA -and (Test-Path $env:LOCALAPPDATA)) { $env:TEMP = Join-Path $env:LOCALAPPDATA "Temp" } if (-not $env:TEMP -or -not (Test-Path $env:TEMP)) { if ($PSScriptRoot) { $env:TEMP = Join-Path $PSScriptRoot "temp" } else { $env:TEMP = Join-Path (Get-Location).Path "temp" } } } if (-not (Test-Path $env:TEMP)) { New-Item -ItemType Directory -Path $env:TEMP -Force | Out-Null } # Função para pausar script e explicar erro function Stop-OnError { param( [string]$ErrorMessage, [string]$ErrorDetails = "", [string]$StepName = "" ) Write-Host "" Write-Host "===============================================================" -ForegroundColor Red Write-Host "ERRO OCORRIDO" -ForegroundColor Red if ($StepName) { Write-Host "Etapa: $StepName" -ForegroundColor Yellow } Write-Host "===============================================================" -ForegroundColor Red Write-Host "" Write-Host "Mensagem de Erro: $ErrorMessage" -ForegroundColor Red if ($ErrorDetails) { Write-Host "" Write-Host "Detalhes: $ErrorDetails" -ForegroundColor Yellow } Write-Host "" Write-Host "O script não pode continuar devido a este erro." -ForegroundColor Yellow Write-Host "Por favor, resolva o problema e tente novamente." -ForegroundColor Yellow Write-Host "" Write-Host "===============================================================" -ForegroundColor Red Write-Host "Saindo..." -ForegroundColor Red Write-Host "===============================================================" -ForegroundColor Red exit 1 } # Função para obter caminho do Steam do registro function Get-SteamPath { $steamPath = $null Write-Host "Procurando instalação do Steam..." -ForegroundColor Gray # Tentar HKCU primeiro (Registro do usuário) $regPath = "HKCU:\Software\Valve\Steam" if (Test-Path $regPath) { $steamPath = (Get-ItemProperty -Path $regPath -Name "SteamPath" -ErrorAction SilentlyContinue).SteamPath if ($steamPath -and (Test-Path $steamPath)) { return $steamPath } } # Tentar HKLM (Registro do sistema) $regPath = "HKLM:\Software\Valve\Steam" if (Test-Path $regPath) { $steamPath = (Get-ItemProperty -Path $regPath -Name "InstallPath" -ErrorAction SilentlyContinue).InstallPath if ($steamPath -and (Test-Path $steamPath)) { return $steamPath } } # Tentar registro 32-bit em sistemas 64-bit $regPath = "HKLM:\Software\WOW6432Node\Valve\Steam" if (Test-Path $regPath) { $steamPath = (Get-ItemProperty -Path $regPath -Name "InstallPath" -ErrorAction SilentlyContinue).InstallPath if ($steamPath -and (Test-Path $steamPath)) { return $steamPath } } return $null } # Função para baixar arquivo com barra de progresso inline function Download-FileWithProgress { param( [string]$Url, [string]$OutFile ) try { $uri = New-Object System.Uri($Url) $uriBuilder = New-Object System.UriBuilder($uri) $timestamp = (Get-Date -Format 'yyyyMMddHHmmss') if ($uriBuilder.Query) { $uriBuilder.Query = $uriBuilder.Query.TrimStart('?') + "&t=" + $timestamp } else { $uriBuilder.Query = "t=" + $timestamp } $cacheBustUrl = $uriBuilder.ToString() $request = [System.Net.HttpWebRequest]::Create($cacheBustUrl) $request.CachePolicy = New-Object System.Net.Cache.RequestCachePolicy([System.Net.Cache.RequestCacheLevel]::NoCacheNoStore) $request.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate") $request.Headers.Add("Pragma", "no-cache") $request.Timeout = 30000 $request.ReadWriteTimeout = 30000 try { $response = $request.GetResponse() } catch { Write-Host " [ERRO] Falha na conexão: $_" -ForegroundColor Red Write-Host " [ERRO] URL: $cacheBustUrl" -ForegroundColor Red throw "Timeout de conexão ou falha ao conectar ao servidor" } $statusCode = [int]$response.StatusCode if ($statusCode -ne 200) { $response.Close() Write-Host " [ERRO] Código de resposta inválido: $statusCode (esperado 200)" -ForegroundColor Red Write-Host " [ERRO] URL: $cacheBustUrl" -ForegroundColor Red throw "Servidor retornou código de status $statusCode ao invés de 200" } $totalLength = $response.ContentLength if ($totalLength -eq 0) { $response.Close() Write-Host " [ERRO] Tamanho de conteúdo inválido: $totalLength (esperado > 0 ou -1 para desconhecido)" -ForegroundColor Red Write-Host " [ERRO] URL: $cacheBustUrl" -ForegroundColor Red throw "Servidor retornou tamanho de conteúdo zero" } $response.Close() $request = [System.Net.HttpWebRequest]::Create($cacheBustUrl) $request.CachePolicy = New-Object System.Net.Cache.RequestCachePolicy([System.Net.Cache.RequestCacheLevel]::NoCacheNoStore) $request.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate") $request.Headers.Add("Pragma", "no-cache") $request.Timeout = -1 $request.ReadWriteTimeout = -1 $response = $null try { $response = $request.GetResponse() } catch { Write-Host " [ERRO] Falha na conexão de download: $_" -ForegroundColor Red Write-Host " [ERRO] URL: $cacheBustUrl" -ForegroundColor Red throw "Falha na conexão durante o download" } try { $outDir = Split-Path $OutFile -Parent if ($outDir -and -not (Test-Path $outDir)) { New-Item -ItemType Directory -Path $outDir -Force | Out-Null } $responseStream = $null $targetStream = $null $responseStream = $response.GetResponseStream() $targetStream = New-Object -TypeName System.IO.FileStream -ArgumentList $OutFile, Create $buffer = New-Object byte[] (10 * 1024) $count = $responseStream.Read($buffer, 0, $buffer.Length) $downloadedBytes = $count $lastUpdate = Get-Date $lastBytesDownloaded = $downloadedBytes $lastBytesUpdateTime = Get-Date $stuckTimeoutSeconds = 60 while ($count -gt 0) { $targetStream.Write($buffer, 0, $count) $count = $responseStream.Read($buffer, 0, $buffer.Length) $downloadedBytes += $count $now = Get-Date if ($downloadedBytes -gt $lastBytesDownloaded) { $lastBytesDownloaded = $downloadedBytes $lastBytesUpdateTime = $now } else { $timeSinceLastBytes = ($now - $lastBytesUpdateTime).TotalSeconds if ($timeSinceLastBytes -ge $stuckTimeoutSeconds) { if (Test-Path $OutFile) { Remove-Item $OutFile -Force -ErrorAction SilentlyContinue } Write-Host "" Write-Host " [ERRO] Download parece estar travado (0 kbps por $stuckTimeoutSeconds segundos)" -ForegroundColor Red Write-Host " [ERRO] Baixado: $downloadedBytes bytes, Esperado: $totalLength bytes" -ForegroundColor Red throw "Download travado - nenhum dado recebido por $stuckTimeoutSeconds segundos" } } if (($now - $lastUpdate).TotalMilliseconds -ge 100) { if ($totalLength -gt 0) { $percentComplete = [math]::Round(($downloadedBytes / $totalLength) * 100, 2) $downloadedMB = [math]::Round($downloadedBytes / 1MB, 2) $totalMB = [math]::Round($totalLength / 1MB, 2) $progressBarLength = [math]::Floor($percentComplete / 2) $progressBar = "=" * $progressBarLength $progressBar = $progressBar.PadRight(50) Write-Host "`r Progresso: [$progressBar] $percentComplete% ($downloadedMB MB / $totalMB MB)" -NoNewline -ForegroundColor Cyan } else { $downloadedMB = [math]::Round($downloadedBytes / 1MB, 2) Write-Host "`r Progresso: Baixado $downloadedMB MB..." -NoNewline -ForegroundColor Cyan } $lastUpdate = $now } } if ($totalLength -gt 0) { $downloadedMB = [math]::Round($downloadedBytes / 1MB, 2) $totalMB = [math]::Round($totalLength / 1MB, 2) $progressBar = "=" * 50 Write-Host "`r Progresso: [$progressBar] 100.00% ($downloadedMB MB / $totalMB MB)" -NoNewline -ForegroundColor Cyan } else { $downloadedMB = [math]::Round($downloadedBytes / 1MB, 2) Write-Host "`r Progresso: Baixado $downloadedMB MB... Completo!" -NoNewline -ForegroundColor Cyan } Write-Host "" return $true } finally { if ($targetStream) { $targetStream.Close() } if ($responseStream) { $responseStream.Close() } if ($response) { $response.Close() } } } catch { Write-Host "" Write-Host " [ERRO] Download falhou: $_" -ForegroundColor Red Write-Host " [ERRO] Detalhes do erro: $($_.Exception.Message)" -ForegroundColor Red if ($_.Exception.InnerException) { Write-Host " [ERRO] Exceção interna: $($_.Exception.InnerException.Message)" -ForegroundColor Red } Write-Host "" throw $_ } } # Função para baixar e extrair com suporte a URL de fallback function Download-AndExtractWithFallback { param( [string]$PrimaryUrl, [string]$FallbackUrl, [string]$TempZipPath, [string]$DestinationPath, [string]$Description ) $urls = @($PrimaryUrl, $FallbackUrl) $lastError = $null foreach ($url in $urls) { $isFallback = ($url -eq $FallbackUrl) try { if (Test-Path $TempZipPath) { Remove-Item -Path $TempZipPath -Force -ErrorAction SilentlyContinue } if ($isFallback) { Write-Host " [INFO] Download primário falhou, tentando URL de fallback..." -ForegroundColor Yellow } Write-Host " Baixando de: $url" -ForegroundColor Gray Download-FileWithProgress -Url $url -OutFile $TempZipPath Write-Host " [SUCESSO] Download completo" -ForegroundColor Green Write-Host " Extraindo para: $DestinationPath" -ForegroundColor Gray Expand-ArchiveWithProgress -ZipPath $TempZipPath -DestinationPath $DestinationPath Write-Host " [SUCESSO] Extração completa" -ForegroundColor Green Remove-Item -Path $TempZipPath -Force -ErrorAction SilentlyContinue return $true } catch { $lastError = $_ $errorMessage = $_.ToString() if ($_.Exception -and $_.Exception.Message) { $errorMessage = $_.Exception.Message } if ($isFallback) { Write-Host " [ERRO] Download de fallback também falhou: $_" -ForegroundColor Red throw "Ambos os downloads primário e de fallback falharam. Último erro: $_" } else { if ($errorMessage -match "Invalid ZIP|corrupted|End of Central Directory|PK signature|ZIP file|Connection.*failed|timeout|stalled|stuck|failed to connect") { Write-Host " [AVISO] Download falhou (possível bloqueio Cloudflare ou problema de conexão), tentando URL de fallback..." -ForegroundColor Yellow continue } else { throw $_ } } } } if ($lastError) { throw $lastError } else { throw "Download falhou por razão desconhecida" } } # Função para extrair arquivo com barra de progresso inline function Expand-ArchiveWithProgress { param( [string]$ZipPath, [string]$DestinationPath ) try { if (-not (Test-Path $ZipPath)) { Write-Host " [ERRO] Arquivo ZIP não encontrado: $ZipPath" -ForegroundColor Red throw "Arquivo ZIP não existe" } $zipFileInfo = Get-Item $ZipPath -ErrorAction Stop if ($zipFileInfo.Length -eq 0) { Write-Host " [ERRO] Arquivo ZIP está vazio (0 bytes)" -ForegroundColor Red throw "Arquivo ZIP está vazio" } $zipStream = $null try { $zipStream = [System.IO.File]::OpenRead($ZipPath) $header = New-Object byte[] 4 $bytesRead = $zipStream.Read($header, 0, 4) if ($bytesRead -lt 4 -or $header[0] -ne 0x50 -or $header[1] -ne 0x4B) { Write-Host " [ERRO] Arquivo não parece ser um ZIP válido (assinatura PK ausente)" -ForegroundColor Red Write-Host " [ERRO] Tamanho do arquivo: $($zipFileInfo.Length) bytes" -ForegroundColor Red throw "Formato de arquivo ZIP inválido" } } finally { if ($zipStream) { $zipStream.Close() } } Add-Type -AssemblyName System.IO.Compression.FileSystem $zip = $null try { $zip = [System.IO.Compression.ZipFile]::OpenRead($ZipPath) } catch { Write-Host " [ERRO] Arquivo ZIP está corrompido ou incompleto" -ForegroundColor Red Write-Host " [ERRO] Tamanho do arquivo: $($zipFileInfo.Length) bytes" -ForegroundColor Red Write-Host " [ERRO] Erro: $($_.Exception.Message)" -ForegroundColor Red throw "Arquivo ZIP está corrompido - download pode ter sido interrompido. Por favor, tente novamente." } try { $entries = $zip.Entries $fileEntries = @() foreach ($entry in $entries) { if (-not ($entry.FullName.EndsWith('\') -or $entry.FullName.EndsWith('/'))) { $fileEntries += $entry } } $totalFiles = $fileEntries.Count if ($totalFiles -eq 0) { Write-Host " [AVISO] Arquivo ZIP não contém arquivos (apenas diretórios)" -ForegroundColor Yellow return $true } $extractedCount = 0 $lastUpdate = Get-Date foreach ($entry in $entries) { $sanitizedPath = $entry.FullName $sanitizedPath = $sanitizedPath.TrimStart('\', '/') $sanitizedPath = $sanitizedPath -replace '^[A-Z]:\\', '' -replace '^/', '' $sanitizedPath = $sanitizedPath -replace '/', '\' $entryPath = Join-Path $DestinationPath $sanitizedPath $resolvedEntryPath = [System.IO.Path]::GetFullPath($entryPath) $resolvedDestination = [System.IO.Path]::GetFullPath($DestinationPath) if (-not $resolvedEntryPath.StartsWith($resolvedDestination, [System.StringComparison]::OrdinalIgnoreCase)) { Write-Host " [AVISO] Pulando caminho potencialmente perigoso: $($entry.FullName)" -ForegroundColor Yellow continue } $entryDir = Split-Path $entryPath -Parent if ($entryDir -and -not (Test-Path $entryDir)) { New-Item -ItemType Directory -Path $entryDir -Force | Out-Null } if ($entry.FullName.EndsWith('\') -or $entry.FullName.EndsWith('/')) { continue } try { [System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $entryPath, $true) $extractedCount++ } catch { if ($_.Exception.Message -match "being used by another process|locked|access.*denied") { Write-Host "" Write-Host " [ERRO] Não é possível extrair $($entry.FullName) - arquivo está bloqueado ou em uso" -ForegroundColor Red Write-Host " [ERRO] Por favor, feche qualquer programa usando este arquivo e tente novamente" -ForegroundColor Red throw "Arquivo bloqueado: $($entry.FullName)" } else { throw } } $now = Get-Date if (($now - $lastUpdate).TotalMilliseconds -ge 50) { $percentComplete = [math]::Round(($extractedCount / $totalFiles) * 100, 2) $progressBarLength = [math]::Floor($percentComplete / 2) $progressBar = "=" * $progressBarLength $progressBar = $progressBar.PadRight(50) Write-Host "`r Progresso: [$progressBar] $percentComplete% ($extractedCount / $totalFiles arquivos)" -NoNewline -ForegroundColor Cyan $lastUpdate = $now } } $progressBar = "=" * 50 Write-Host "`r Progresso: [$progressBar] 100.00% ($totalFiles / $totalFiles arquivos)" -NoNewline -ForegroundColor Cyan Write-Host "" return $true } finally { if ($zip) { $zip.Dispose() } } } catch { Write-Host "" throw $_ } } # Função para matar processos do Steam com retry e verificação function Stop-SteamProcesses { $maxAttempts = 3 $attempt = 0 $steamServiceNames = @("Steam Client Service", "SteamService", "Steam") foreach ($serviceName in $steamServiceNames) { try { $steamService = Get-Service -Name $serviceName -ErrorAction SilentlyContinue if ($steamService -and $steamService.Status -eq 'Running') { Write-Host " [INFO] Parando $serviceName..." -ForegroundColor Gray try { Stop-Service -Name $serviceName -Force -ErrorAction Stop Write-Host " [SUCESSO] $serviceName parado" -ForegroundColor Green Start-Sleep -Seconds 1 break } catch { Write-Host " [AVISO] Não foi possível parar $serviceName (pode exigir privilégios de administrador): $_" -ForegroundColor Yellow } } } catch { continue } } while ($attempt -lt $maxAttempts) { $attempt++ $steamProcesses = Get-Process -Name "steam*" -ErrorAction SilentlyContinue if (-not $steamProcesses) { if ($attempt -eq 1) { Write-Host " [INFO] Nenhum processo Steam encontrado em execução" -ForegroundColor Cyan } return $true } if ($attempt -gt 1) { Write-Host " [INFO] Tentativa $attempt de $maxAttempts para matar processos restantes..." -ForegroundColor Yellow } foreach ($proc in $steamProcesses) { if ($proc.Name -eq "SteamService") { $serviceStoppedInLoop = $false foreach ($serviceName in $steamServiceNames) { try { $steamService = Get-Service -Name $serviceName -ErrorAction SilentlyContinue if ($steamService -and $steamService.Status -eq 'Running') { Write-Host " [INFO] Tentando parar SteamService como serviço do Windows ($serviceName)..." -ForegroundColor Gray Stop-Service -Name $serviceName -Force -ErrorAction Stop Write-Host " [SUCESSO] SteamService parado via controle de serviço" -ForegroundColor Green Start-Sleep -Seconds 1 $serviceStoppedInLoop = $true break } } catch { continue } } if ($serviceStoppedInLoop) { continue } } try { $proc.Kill() Write-Host " [INFO] Processo morto: $($proc.Name) (PID: $($proc.Id))" -ForegroundColor Gray } catch { try { Stop-Process -Id $proc.Id -Force -ErrorAction Stop Write-Host " [INFO] Processo morto forçadamente: $($proc.Name) (PID: $($proc.Id))" -ForegroundColor Gray } catch { if ($proc.Name -eq "SteamService") { Write-Host " [AVISO] Não foi possível matar SteamService (PID: $($proc.Id)) - este é um serviço do Windows" -ForegroundColor Yellow Write-Host " [INFO] SteamService pode exigir privilégios de administrador para parar. O script continuará mesmo assim." -ForegroundColor Yellow } else { Write-Host " [AVISO] Não foi possível matar processo: $($proc.Name) (PID: $($proc.Id))" -ForegroundColor Yellow } } } } Start-Sleep -Seconds 2 Write-Host "" $remainingProcesses = Get-Process -Name "steam*" -ErrorAction SilentlyContinue if (-not $remainingProcesses) { Write-Host " Aguardando DLLs serem totalmente liberadas..." -ForegroundColor Gray Start-Sleep -Seconds 3 $finalCheck = Get-Process -Name "steam*" -ErrorAction SilentlyContinue if ($finalCheck) { Write-Host " [AVISO] Steam parece ter reiniciado, matando novamente..." -ForegroundColor Yellow foreach ($proc in $finalCheck) { try { Stop-Process -Id $proc.Id -Force -ErrorAction Stop Write-Host " [INFO] Processo reiniciado morto: $($proc.Name) (PID: $($proc.Id))" -ForegroundColor Gray } catch { Write-Host " [AVISO] Não foi possível matar processo reiniciado: $($proc.Name)" -ForegroundColor Yellow } } Start-Sleep -Seconds 2 $stillRunning = Get-Process -Name "steam*" -ErrorAction SilentlyContinue if ($stillRunning) { Write-Host " [AVISO] Steam continua reiniciando - isso pode indicar um processo watchdog" -ForegroundColor Yellow continue } else { Write-Host " [SUCESSO] Todos os processos Steam terminados" -ForegroundColor Green return $true } } else { Write-Host " [SUCESSO] Todos os processos Steam terminados" -ForegroundColor Green return $true } } else { Write-Host " [AVISO] Alguns processos ainda estão em execução, tentando novamente..." -ForegroundColor Yellow } } $finalCheck = Get-Process -Name "steam*" -ErrorAction SilentlyContinue if ($finalCheck) { $nonServiceProcesses = $finalCheck | Where-Object { $_.Name -ne "SteamService" } if ($nonServiceProcesses) { $processList = ($nonServiceProcesses | ForEach-Object { "$($_.Name) (PID: $($_.Id))" }) -join ", " $errorMsg = "Os seguintes processos Steam não puderam ser terminados: $processList" $errorDetails = "Steam pode ter um processo watchdog que o reinicia automaticamente. Por favor, feche manualmente o Steam e quaisquer processos relacionados, depois tente novamente." Stop-OnError -ErrorMessage "Falha ao terminar todos os processos Steam" -ErrorDetails $errorDetails -StepName "Etapa 1" } else { Write-Host " [INFO] Apenas SteamService ainda está em execução (serviço do Windows - não bloqueia)" -ForegroundColor Cyan Write-Host " [SUCESSO] Todos os processos Steam bloqueantes terminados" -ForegroundColor Green } } return $true } # ============================================ # PARTE 1: FIX-ST # ============================================ Write-Host "===============================================================" -ForegroundColor Cyan Write-Host "PARTE 1: Correção do Steam (fix-st)" -ForegroundColor Cyan Write-Host "===============================================================" -ForegroundColor Cyan Write-Host "" # Etapa 1: Encontrar localização de instalação do Steam através do registro Write-Host "[Etapa 1] Procurando localização de instalação do Steam..." -ForegroundColor Yellow $steamPath = Get-SteamPath if (-not $steamPath) { Write-Host "ERRO: Não foi possível encontrar instalação do Steam no registro" -ForegroundColor Red exit 1 } Write-Host "Instalação do Steam encontrada: $steamPath" -ForegroundColor Green # Etapa 2: Verificar se hid.dll existe no diretório do Steam Write-Host "`n[Etapa 2] Verificando se AmericanKey está instalado..." -ForegroundColor Yellow $hidDllPath = Join-Path $steamPath "hid.dll" if (Test-Path $hidDllPath) { Write-Host "hid.dll encontrado em: $hidDllPath" -ForegroundColor Green } else { Write-Host "hid.dll NÃO encontrado em: $hidDllPath" -ForegroundColor Red Write-Host "Não foi encontrado o arquivo necessário para o AmericanKey funcionar!" -ForegroundColor Red Write-Host "" Write-Host "Para instalar o AmericanKey, execute o seguinte comando no PowerShell:" -ForegroundColor Yellow Write-Host "irm steam.run | iex" -ForegroundColor Cyan Write-Host "" Write-Host "Pressione Enter para sair..." Read-Host exit 1 } # Etapa 3: Contar arquivos .lua em config/stplug-in Write-Host "`n[Etapa 3] Contando arquivos .lua em config/stplug-in..." -ForegroundColor Yellow $stplugInPath = Join-Path $steamPath "config\stplug-in" if (Test-Path $stplugInPath) { $luaFiles = Get-ChildItem -Path $stplugInPath -Filter "*.lua" -ErrorAction SilentlyContinue $luaCount = $luaFiles.Count if ($luaCount -eq 0) { Write-Host "ERRO: 0 arquivos .lua encontrados em $stplugInPath" -ForegroundColor Red } else { Write-Host "Encontrados $luaCount arquivo(s) .lua em $stplugInPath" -ForegroundColor Green } } else { Write-Host "ERRO: Diretório não encontrado: $stplugInPath" -ForegroundColor Red Write-Host "ERRO: 0 arquivos .lua encontrados (diretório não existe)" -ForegroundColor Red } # Pré-etapa 4: verificar existência da pasta de backup Write-Host "`n[Pré-Etapa 4] Verificando pasta de backup..." $backupPath = Join-Path $steamPath "cache-backup" if (Test-Path $backupPath) { Write-Host "Pasta de backup já existe em $backupPath" -ForegroundColor Yellow $restoreChoice = Read-Host "Você deseja restaurar o backup ao invés disso? (s/n)" if ($restoreChoice -eq "s") { Write-Host "Fechando processos do Steam..." -ForegroundColor Gray Get-Process -Name "steam*" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue Write-Host "Aguardando Steam fechar..." -ForegroundColor Gray Start-Sleep -Seconds 3 Write-Host "Restaurando backup..." -ForegroundColor Yellow $items = Get-ChildItem -Path $backupPath -Force -ErrorAction SilentlyContinue foreach ($item in $items) { $destination = Join-Path $steamPath $item.Name Move-Item -Path $item.FullName -Destination $destination -Force -ErrorAction SilentlyContinue } Write-Host "Backup restaurado." -ForegroundColor Green Write-Host "Limpando pasta de backup..." -ForegroundColor Gray Remove-Item -Path $backupPath -Recurse -Force -ErrorAction SilentlyContinue Write-Host "Pasta de backup limpa." -ForegroundColor Green Write-Host "Iniciando Steam (beta desabilitado)..." -ForegroundColor Gray $steamExe = Join-Path $steamPath "steam.exe" if (Test-Path $steamExe) { Start-Process -FilePath $steamExe -ArgumentList "-clearbeta" Write-Host "Steam iniciado." -ForegroundColor Green } else { Write-Host "ERRO: steam.exe não encontrado em $steamExe" -ForegroundColor Red } Write-Host "`nPressione Enter para sair..." Read-Host exit 0 } else { Write-Host "Continuando com limpeza de cache..." -ForegroundColor Gray } } else { Write-Host "Nenhuma pasta de backup existente encontrada. Prosseguindo..." -ForegroundColor Green } # Etapa 4: Limpar caches do Steam preservando conquistas Write-Host "`n[Etapa 4] Limpando caches do Steam..." -ForegroundColor Yellow $backupPath = Join-Path $steamPath "cache-backup" Write-Host "Criando pasta de backup..." -ForegroundColor Gray New-Item -ItemType Directory -Path $backupPath -Force | Out-Null Write-Host "Fechando processos do Steam..." -ForegroundColor Gray Get-Process -Name "steam*" -ErrorAction SilentlyContinue | Stop-Process -ErrorAction SilentlyContinue Write-Host "Aguardando Steam fechar..." -ForegroundColor Gray Start-Sleep -Seconds 3 Write-Host "Limpando caches de app e depot..." -ForegroundColor Gray Start-Sleep -Seconds 1 $appcachePath = Join-Path $steamPath "appcache" $appcacheBackupPath = Join-Path $backupPath "appcache" if (Test-Path $appcachePath) { New-Item -ItemType Directory -Path $appcacheBackupPath -Force | Out-Null Get-ChildItem -Path $appcachePath -Force -Exclude "stats" | Move-Item -Destination $appcacheBackupPath -Force -ErrorAction SilentlyContinue Copy-Item -Path (Join-Path $appcachePath "stats") -Destination $appcacheBackupPath -Recurse -Force -ErrorAction SilentlyContinue } $depotcachePath = Join-Path $steamPath "depotcache" $depotcacheBackupPath = Join-Path $backupPath "depotcache" if (Test-Path $depotcachePath) { New-Item -ItemType Directory -Path $depotcacheBackupPath -Force | Out-Null Get-ChildItem -Path $depotcachePath -Force | Move-Item -Destination $depotcacheBackupPath -Force -ErrorAction SilentlyContinue Remove-Item -Path $depotcachePath -Recurse -Force -ErrorAction SilentlyContinue } Write-Host "Limpando caches de usuário..." -ForegroundColor Gray $userdataPath = Join-Path $steamPath "userdata" $userCount = 0 if (Test-Path $userdataPath) { $userFolders = Get-ChildItem -Path $userdataPath -Directory -ErrorAction SilentlyContinue foreach ($userFolder in $userFolders) { $userConfigPath = Join-Path $userFolder.FullName "config" if (Test-Path $userConfigPath) { $userCount++ $userBackupPath = Join-Path -Path $backupPath -ChildPath (Join-Path "userdata" $userFolder.Name) if (-not (Test-Path $userBackupPath)) { New-Item -ItemType Directory -Path $userBackupPath -Force | Out-Null } $userConfigBackup = Join-Path $userBackupPath "config" Move-Item -Path $userConfigPath -Destination $userConfigBackup -Force -ErrorAction SilentlyContinue Write-Host "Restaurando tempo de jogo para $($userFolder.Name) ..." -ForegroundColor Gray Start-Sleep -Seconds 1 if (Test-Path $userBackupPath) { if (-not (Test-Path (Split-Path $userConfigPath -Parent))) { New-Item -ItemType Directory -Path (Split-Path $userConfigPath -Parent) -Force | Out-Null } New-Item -ItemType Directory -Path $userConfigPath -Force | Out-Null Copy-Item (Join-Path $userBackupPath "config\localconfig.vdf") -Destination (Join-Path $userConfigPath "localconfig.vdf") -Force -ErrorAction SilentlyContinue Write-Host "Tempo de jogo para $($userFolder.Name) restaurado." -ForegroundColor Green } } } if ($userCount -gt 0) { Write-Host "Limpando cache de usuário para $userCount userid(s)..." -ForegroundColor Gray } } Write-Host "Cache de usuário limpo!" -ForegroundColor Green Write-Host "" Write-Host "===============================================================" -ForegroundColor Cyan Write-Host "PARTE 1 CONCLUÍDA" -ForegroundColor Green Write-Host "===============================================================" -ForegroundColor Cyan Write-Host "" # ============================================ # PARTE 2: STEAM DOWNGRADER # ============================================ Write-Host "===============================================================" -ForegroundColor Cyan Write-Host "PARTE 2: Downgrader do Steam 32-bit" -ForegroundColor Cyan Write-Host "===============================================================" -ForegroundColor Cyan Write-Host "" # Etapa 0: Obter caminho do Steam do registro Write-Host "Etapa 0: Localizando instalação do Steam..." -ForegroundColor Yellow $steamPath = Get-SteamPath $steamExePath = $null if (-not $steamPath) { Write-Host " [ERRO] Instalação do Steam não encontrada no registro." -ForegroundColor Red Write-Host " Por favor, certifique-se de que o Steam está instalado no seu sistema." -ForegroundColor Yellow Write-Host "" Write-Host "===============================================================" -ForegroundColor DarkYellow Write-Host "Saindo..." -ForegroundColor Green Write-Host "===============================================================" -ForegroundColor DarkYellow exit } $steamExePath = Join-Path $steamPath "Steam.exe" if (-not (Test-Path $steamExePath)) { Write-Host " [ERRO] Steam.exe não encontrado em: $steamExePath" -ForegroundColor Red Write-Host " O diretório do Steam existe mas Steam.exe está ausente." -ForegroundColor Yellow Write-Host "" Write-Host "===============================================================" -ForegroundColor DarkYellow Write-Host "Saindo..." -ForegroundColor Green Write-Host "===============================================================" -ForegroundColor DarkYellow exit } Write-Host " [SUCESSO] Steam encontrado!" -ForegroundColor Green Write-Host " Localização: $steamPath" -ForegroundColor White Write-Host "" # Etapa 1: Matar todos os processos do Steam Write-Host "Etapa 1: Matando todos os processos do Steam..." -ForegroundColor Yellow Stop-SteamProcesses Write-Host "" # Etapa 2: Baixar e extrair Steam x32 Latest Build Write-Host "Etapa 2: Baixando e extraindo Steam x32 Latest Build..." -ForegroundColor Yellow $steamZipUrl = "https://github.com/madoiscool/lt_api_links/releases/download/unsteam/latest32bitsteam.zip" $steamZipFallbackUrl = "http://files.luatools.work/OneOffFiles/latest32bitsteam.zip" $tempSteamZip = Join-Path $env:TEMP "latest32bitsteam.zip" try { Download-AndExtractWithFallback -PrimaryUrl $steamZipUrl -FallbackUrl $steamZipFallbackUrl -TempZipPath $tempSteamZip -DestinationPath $steamPath -Description "Steam x32 Latest Build" Write-Host "" } catch { if (Test-Path $tempSteamZip) { Remove-Item -Path $tempSteamZip -Force -ErrorAction SilentlyContinue } $errorMsg = $_.Exception.Message if (-not $errorMsg) { $errorMsg = $_.ToString() } Stop-OnError -ErrorMessage "Falha ao baixar ou extrair Steam x32 Latest Build" -ErrorDetails $errorMsg -StepName "Etapa 2" } # Etapa 3: Baixar e extrair arquivo zip (apenas se millennium.dll ou user32.dll estiver presente - para substituí-lo) Write-Host "Etapa 3: Verificando build Millennium..." -ForegroundColor Yellow $millenniumDll = Get-ChildItem -Path $steamPath -Filter "millennium.dll" -ErrorAction SilentlyContinue | Select-Object -First 1 $user32Dll = Get-ChildItem -Path $steamPath -Filter "user32.dll" -ErrorAction SilentlyContinue | Select-Object -First 1 $hasMillennium = ($millenniumDll -and (Test-Path $millenniumDll.FullName)) $hasUser32 = ($user32Dll -and (Test-Path $user32Dll.FullName)) if ($hasMillennium -or $hasUser32) { $foundDlls = @() if ($hasMillennium) { $foundDlls += "millennium.dll" Write-Host " [INFO] millennium.dll encontrado" -ForegroundColor Yellow Write-Host " Localização: $($millenniumDll.FullName)" -ForegroundColor White } if ($hasUser32) { $foundDlls += "user32.dll" Write-Host " [INFO] user32.dll encontrado" -ForegroundColor Yellow Write-Host " Localização: $($user32Dll.FullName)" -ForegroundColor White } Write-Host " [INFO] Baixando e extraindo build Millennium para substituir: $($foundDlls -join ', ')" -ForegroundColor Yellow function Unlock-AndRemoveDll { param([string]$DllPath) $maxRetries = 5 $retryDelay = 2 for ($i = 0; $i -lt $maxRetries; $i++) { try { $fileStream = [System.IO.File]::Open($DllPath, 'Open', 'ReadWrite', 'None') $fileStream.Close() $fileStream.Dispose() Remove-Item -Path $DllPath -Force -ErrorAction Stop Write-Host " [INFO] DLL bloqueada removida com sucesso (tentativa $($i + 1))" -ForegroundColor Gray return $true } catch { if ($i -lt $maxRetries - 1) { Write-Host " [INFO] DLL está bloqueada, aguardando ${retryDelay}s antes de tentar novamente ($($i + 1)/$maxRetries)..." -ForegroundColor Yellow Start-Sleep -Seconds $retryDelay } else { Write-Host " [AVISO] Não foi possível desbloquear DLL após $maxRetries tentativas: $_" -ForegroundColor Yellow return $false } } } return $false } $dllsToUnlock = @() if ($hasMillennium) { $dllsToUnlock += @{ Path = $millenniumDll.FullName; Name = "millennium.dll" } } if ($hasUser32) { $dllsToUnlock += @{ Path = $user32Dll.FullName; Name = "user32.dll" } } foreach ($dll in $dllsToUnlock) { Write-Host " Tentando desbloquear $($dll.Name)..." -ForegroundColor Gray $unlocked = Unlock-AndRemoveDll -DllPath $dll.Path if (-not $unlocked) { $errorMsg = "Não foi possível desbloquear $($dll.Name) após múltiplas tentativas. O arquivo pode estar bloqueado por outro processo (antivírus, Windows Explorer, etc.)." Stop-OnError -ErrorMessage "Falha ao desbloquear $($dll.Name)" -ErrorDetails $errorMsg -StepName "Etapa 3" } } $zipUrl = "https://github.com/madoiscool/lt_api_links/releases/download/unsteam/luatoolsmilleniumbuild.zip" $zipFallbackUrl = "http://files.luatools.work/OneOffFiles/luatoolsmilleniumbuild.zip" $tempZip = Join-Path $env:TEMP "luatoolsmilleniumbuild.zip" try { Download-AndExtractWithFallback -PrimaryUrl $zipUrl -FallbackUrl $zipFallbackUrl -TempZipPath $tempZip -DestinationPath $steamPath -Description "Build Millennium" $verificationFailed = $false $verifiedDlls = @() if ($hasMillennium) { $newMillenniumDll = Get-ChildItem -Path $steamPath -Filter "millennium.dll" -ErrorAction SilentlyContinue | Select-Object -First 1 if ($newMillenniumDll -and (Test-Path $newMillenniumDll.FullName)) { Write-Host " [SUCESSO] millennium.dll verificado após extração" -ForegroundColor Green Write-Host " Localização: $($newMillenniumDll.FullName)" -ForegroundColor Gray $verifiedDlls += "millennium.dll" } else { Write-Host " [AVISO] millennium.dll não foi encontrado após extração" -ForegroundColor Yellow $verificationFailed = $true } } if ($hasUser32) { $newUser32Dll = Get-ChildItem -Path $steamPath -Filter "user32.dll" -ErrorAction SilentlyContinue | Select-Object -First 1 if ($newUser32Dll -and (Test-Path $newUser32Dll.FullName)) { Write-Host " [SUCESSO] user32.dll verificado após extração" -ForegroundColor Green Write-Host " Localização: $($newUser32Dll.FullName)" -ForegroundColor Gray $verifiedDlls += "user32.dll" } else { Write-Host " [AVISO] user32.dll não foi encontrado após extração" -ForegroundColor Yellow $verificationFailed = $true } } if ($verificationFailed) { $missingDlls = @() if ($hasMillennium -and "millennium.dll" -notin $verifiedDlls) { $missingDlls += "millennium.dll" } if ($hasUser32 -and "user32.dll" -notin $verifiedDlls) { $missingDlls += "user32.dll" } $errorMsg = "Os seguintes DLL(s) não foram encontrados após extração: $($missingDlls -join ', '). A substituição pode ter falhado." Stop-OnError -ErrorMessage "Falha na verificação de DLL Millennium" -ErrorDetails $errorMsg -StepName "Etapa 3" } Write-Host "" } catch { if (Test-Path $tempZip) { Remove-Item -Path $tempZip -Force -ErrorAction SilentlyContinue } $errorMsg = $_.Exception.Message if (-not $errorMsg) { $errorMsg = $_.ToString() } Stop-OnError -ErrorMessage "Falha ao baixar ou extrair build Millennium" -ErrorDetails $errorMsg -StepName "Etapa 3" } } else { Write-Host " [INFO] Nem millennium.dll nem user32.dll encontrados, pulando download e extração" -ForegroundColor Cyan Write-Host "" } # Etapa 4: Criar arquivo steam.cfg Write-Host "Etapa 4: Criando arquivo steam.cfg..." -ForegroundColor Yellow $steamCfgPath = Join-Path $steamPath "steam.cfg" $cfgContent = "BootStrapperInhibitAll=enable`nBootStrapperForceSelfUpdate=disable" Set-Content -Path $steamCfgPath -Value $cfgContent -Force Write-Host " [SUCESSO] steam.cfg criado!" -ForegroundColor Green Write-Host " Localização: $steamCfgPath" -ForegroundColor White Write-Host "" # Etapa 5: Iniciar Steam Write-Host "Etapa 5: Iniciando Steam..." -ForegroundColor Yellow $arguments = @("-clearbeta") Write-Host " Executável: $steamExePath" -ForegroundColor Gray Write-Host " Argumentos: $($arguments -join ' ')" -ForegroundColor Gray Write-Host "" try { $process = Start-Process -FilePath $steamExePath -ArgumentList $arguments -PassThru -WindowStyle Normal Write-Host " [SUCESSO] Steam iniciado com sucesso!" -ForegroundColor Green Write-Host " ID do Processo: $($process.Id)" -ForegroundColor Cyan Write-Host "" Write-Host "Steam está agora em execução com o arquivo de configuração." -ForegroundColor White Write-Host "" } catch { $errorMsg = $_.Exception.Message if (-not $errorMsg) { $errorMsg = $_.ToString() } Stop-OnError -ErrorMessage "Falha ao iniciar Steam" -ErrorDetails $errorMsg -StepName "Etapa 5" } # Arte ASCII Write-Host "" Write-Host ' _...Q._' -ForegroundColor Cyan Write-Host ' .'' ''.' -ForegroundColor Cyan Write-Host ' / \' -ForegroundColor Cyan Write-Host ' ;.-""--.._ |' -ForegroundColor Cyan Write-Host ' /''-._____..-''\|' -ForegroundColor Cyan Write-Host ' .'' ; o o |`;' -ForegroundColor Cyan Write-Host ' / /| () ; \' -ForegroundColor Cyan Write-Host ' _.-, ''-'' ; ''.__.-'' \ \' -ForegroundColor Cyan Write-Host '.-"`, | \_ / `''`' -ForegroundColor Cyan Write-Host ' ''._`.; ._ / `''--.,_=-;_' -ForegroundColor Cyan Write-Host ' \ \| `\ .\_ /` \ `._' -ForegroundColor Cyan Write-Host ' \ \ `/ ``---| \ (~' -ForegroundColor Cyan Write-Host ' \ \. | o , \ (~ (~ ______________' -ForegroundColor Cyan Write-Host ' \ \`_\ _..-'' \ (\(~ |.------------.|' -ForegroundColor Cyan Write-Host ' \/ `` / \(~/ || TUDO PRONTO!! ||' -ForegroundColor Cyan Write-Host ' \__ __..-'' - ''. || """" """" ||' -ForegroundColor Cyan Write-Host ' \ \``` \ || discord.gg ||' -ForegroundColor Cyan Write-Host ' ;\ \o ; || /americankey||' -ForegroundColor Cyan Write-Host ' | \ \ | ||____________||' -ForegroundColor Cyan Write-Host ' ; \ \ ; ''------..------''' -ForegroundColor Cyan Write-Host ' \ \ \ _.-''\ / ||' -ForegroundColor Cyan Write-Host ' ''. \-'' \ .'' ||' -ForegroundColor Cyan Write-Host ' _.-" '' \-'' .-||-.' -ForegroundColor Cyan Write-Host ' \ '' '' '' \ ''..---.- ''' -ForegroundColor Cyan Write-Host ' \ '' '' _.'' ' -ForegroundColor Cyan Write-Host ' \'' '' _.-''' -ForegroundColor Cyan Write-Host ' \ _.-''' -ForegroundColor Cyan Write-Host ' `' -ForegroundColor Cyan Write-Host "" Write-Host "===============================================================" -ForegroundColor Cyan Write-Host "Se você quiser reverter a limpeza de cache:" -ForegroundColor Yellow Write-Host "Execute este script novamente e escolha 's' quando solicitado" -ForegroundColor Yellow Write-Host "OU mova manualmente as pastas dentro de $backupPath de volta para $steamPath" -ForegroundColor Yellow Write-Host "===============================================================" -ForegroundColor Cyan Write-Host "" Write-Host "Seus jogos DEVEM funcionar agora, aproveite! Script por @piqseu - traduzido por @c7pw no discord" -ForegroundColor Cyan Write-Host "`nPressione Enter para sair..." Read-Host