Модлоадер RustexRemake: агент, патч лаунчера, установщик и сборка
Моды грузятся через -javaagent, game.jar не патчится, переживают ре-обфускацию. Что внутри: - агент rsx-bridge.jar: профиль сборки игры, патчи A2/A6, загрузка модов через родной загрузчик игры (ilxq -> special.Main) - патч лаунчера: окно выбора «С модами / Ванилла» по кнопке «Играть» и защита от автоапдейта лаунчера - install/uninstall: всё ставится в %LOCALAPPDATA%\rsx-mod, пути не хардкодятся - build: три готовых артефакта в dist, нужен только JDK - testserver: локальный сервер, принимает любой ник и токен Проверено на живом клиенте: мод грузится и выполняется в игровом потоке, в логе видно игрока и мир.
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
# Builds everything the installer needs, into dist\:
|
||||
#
|
||||
# dist\rsx-bridge.jar the agent (-javaagent), Java 8
|
||||
# dist\rsx-api.jar API a mod compiles against
|
||||
# dist\rsx-launcher-patch.jar launcher patcher with ASM inside
|
||||
# dist\mod-template\ ready-to-edit mod project
|
||||
#
|
||||
# Only a JDK is required: ASM is vendored under third_party\asm so the build
|
||||
# works offline and the patcher jar is self-contained.
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$Repo = Split-Path -Parent $PSScriptRoot
|
||||
if (-not $Repo) { $Repo = $PSCommandPath | Split-Path -Parent | Split-Path -Parent }
|
||||
$Dist = Join-Path $Repo 'dist'
|
||||
$Out = Join-Path $Repo 'build'
|
||||
$Asm = @(Get-ChildItem (Join-Path $Repo 'third_party\asm') -Filter '*.jar' |
|
||||
ForEach-Object { $_.FullName })
|
||||
|
||||
function Say($text) { Write-Host " $text" }
|
||||
|
||||
if (-not (Get-Command javac -ErrorAction SilentlyContinue)) {
|
||||
Write-Host ' Нужен JDK (javac) в PATH.' -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
if ($Asm.Count -lt 2) {
|
||||
Write-Host ' Не найдены jar-ки ASM в third_party\asm.' -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $Dist, $Out | Out-Null
|
||||
|
||||
# ---------------------------------------------------------------- agent
|
||||
$agentSrc = Join-Path $Repo 'bridge\src\main\java'
|
||||
$agentOut = Join-Path $Out 'agent'
|
||||
Remove-Item $agentOut -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path $agentOut | Out-Null
|
||||
$agentFiles = Get-ChildItem $agentSrc -Recurse -Filter '*.java' | ForEach-Object { $_.FullName }
|
||||
& javac -encoding UTF-8 --release 8 -nowarn -d $agentOut $agentFiles
|
||||
if ($LASTEXITCODE -ne 0) { Write-Host ' Агент не собрался.' -ForegroundColor Red; exit 1 }
|
||||
Say "агент скомпилирован ($($agentFiles.Count) файлов)"
|
||||
|
||||
$manifest = Join-Path $Out 'agent-manifest.txt'
|
||||
@"
|
||||
Manifest-Version: 1.0
|
||||
Premain-Class: rsx.RsxAgent
|
||||
Can-Redefine-Classes: false
|
||||
Can-Retransform-Classes: true
|
||||
|
||||
"@ | Set-Content -LiteralPath $manifest -Encoding ASCII
|
||||
|
||||
Push-Location $agentOut
|
||||
& jar cfm (Join-Path $Dist 'rsx-bridge.jar') $manifest -C $agentOut .
|
||||
Pop-Location
|
||||
Say "rsx-bridge.jar ($((Get-Item (Join-Path $Dist 'rsx-bridge.jar')).Length) байт)"
|
||||
|
||||
# ---------------------------------------------------------------- api
|
||||
$apiOut = Join-Path $Out 'api'
|
||||
Remove-Item $apiOut -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path $apiOut | Out-Null
|
||||
$apiFiles = Get-ChildItem (Join-Path $Repo 'bridge\src\main\java\net') -Recurse -Filter '*.java' |
|
||||
ForEach-Object { $_.FullName }
|
||||
# the API delegates to the agent internals, so they have to be on the
|
||||
# classpath; only net/ classes end up in the published jar
|
||||
& javac -encoding UTF-8 --release 8 -nowarn -cp $agentOut -d $apiOut $apiFiles
|
||||
if ($LASTEXITCODE -ne 0) { Write-Host ' API не собрался.' -ForegroundColor Red; exit 1 }
|
||||
Push-Location $apiOut
|
||||
& jar cf (Join-Path $Dist 'rsx-api.jar') .
|
||||
Pop-Location
|
||||
Say "rsx-api.jar ($((Get-Item (Join-Path $Dist 'rsx-api.jar')).Length) байт)"
|
||||
|
||||
# ---------------------------------------------------------------- patcher
|
||||
$patchOut = Join-Path $Out 'patcher'
|
||||
Remove-Item $patchOut -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path $patchOut | Out-Null
|
||||
$patchSrc = Join-Path $Repo 'launcher-patch\src'
|
||||
# Choice needs JavaFX, which only the launcher ships; it is compiled separately
|
||||
# below with those jars on the classpath
|
||||
$patchFiles = Get-ChildItem $patchSrc -Recurse -Filter '*.java' |
|
||||
Where-Object { $_.Name -ne 'Choice.java' } |
|
||||
ForEach-Object { $_.FullName }
|
||||
& javac -encoding UTF-8 --release 8 -nowarn -cp ($Asm -join ';') -d $patchOut $patchFiles
|
||||
if ($LASTEXITCODE -ne 0) { Write-Host ' Патчер не собрался.' -ForegroundColor Red; exit 1 }
|
||||
|
||||
# Choice talks to JavaFX, so the launcher's own runtime provides those classes
|
||||
$javafx = Join-Path $env:APPDATA 'kjstudio\launcher\runtime\javafx\lib'
|
||||
if (Test-Path $javafx) {
|
||||
$fx = @(Get-ChildItem $javafx -Filter '*.jar' | ForEach-Object { $_.FullName })
|
||||
& javac -encoding UTF-8 --release 8 -nowarn -cp ($fx -join ';') -d $patchOut `
|
||||
(Join-Path $patchSrc 'rsx\Choice.java')
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host ' Choice не собрался: нужны JavaFX-jar-ки лаунчера.' -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
Say 'ВНИМАНИЕ: JavaFX лаунчера не найден, Choice собран вслепую'
|
||||
}
|
||||
|
||||
# shade ASM so the jar runs on any machine
|
||||
$shade = $patchOut
|
||||
foreach ($jar in $Asm) {
|
||||
Push-Location $shade
|
||||
& jar xf $jar
|
||||
Pop-Location
|
||||
}
|
||||
Remove-Item (Join-Path $shade 'META-INF\MANIFEST.MF') -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item (Join-Path $shade 'META-INF\versions') -Recurse -Force -ErrorAction SilentlyContinue
|
||||
|
||||
$patchManifest = Join-Path $Out 'patcher-manifest.txt'
|
||||
@"
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: LauncherPatch
|
||||
|
||||
"@ | Set-Content -LiteralPath $patchManifest -Encoding ASCII
|
||||
Push-Location $shade
|
||||
& jar cfm (Join-Path $Dist 'rsx-launcher-patch.jar') $patchManifest -C $shade .
|
||||
Pop-Location
|
||||
Say "rsx-launcher-patch.jar ($((Get-Item (Join-Path $Dist 'rsx-launcher-patch.jar')).Length) байт)"
|
||||
|
||||
# ---------------------------------------------------------------- mod template
|
||||
$tpl = Join-Path $Dist 'mod-template'
|
||||
Remove-Item $tpl -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path "$tpl\libs", "$tpl\src\main\java\example" | Out-Null
|
||||
Copy-Item (Join-Path $Repo 'mod-template\build.gradle') $tpl -Force
|
||||
Copy-Item (Join-Path $Repo 'mod-template\settings.gradle') $tpl -Force
|
||||
Copy-Item (Join-Path $Repo 'mod-template\src\main\java\example\ExampleMod.java') `
|
||||
"$tpl\src\main\java\example\" -Force
|
||||
Copy-Item (Join-Path $Dist 'rsx-api.jar') "$tpl\libs\" -Force
|
||||
@'
|
||||
@echo off
|
||||
rem Builds this mod and drops the jar into the client's mods folder.
|
||||
cd /d "%~dp0"
|
||||
call gradle jar
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo Скопируй build\libs\example-mod.jar в working_dir\mods
|
||||
'@ | Set-Content -LiteralPath (Join-Path $tpl 'build.cmd') -Encoding ASCII
|
||||
Say 'mod-template готов'
|
||||
|
||||
Write-Host ''
|
||||
Write-Host ' Готово:' -ForegroundColor Green
|
||||
Get-ChildItem $Dist -File | ForEach-Object { Write-Host " $($_.Name)" }
|
||||
@@ -0,0 +1,28 @@
|
||||
# Points the vendor's hardcoded server address at this machine so the client
|
||||
# reaches the local stand-in server instead of the real one.
|
||||
#
|
||||
# The client keeps 185.207.214.85 inside its own code (both the /server-ping
|
||||
# URL and the connect target), so there is no in-game switch for it - the only
|
||||
# way is a hosts entry. Run this once from an elevated prompt.
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$hosts = Join-Path $env:SystemRoot 'System32\drivers\etc\hosts'
|
||||
$marker = '# rsx modloader test server'
|
||||
$line = '127.0.0.1 185.207.214.85'
|
||||
|
||||
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$isAdmin = (New-Object Security.Principal.WindowsPrincipal($id)).IsInRole(
|
||||
[Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
if (-not $isAdmin) {
|
||||
Write-Host ' Нужны права администратора: запусти PowerShell от администратора.' -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
$content = @(Get-Content -LiteralPath $hosts |
|
||||
Where-Object { $_ -notmatch [regex]::Escape($marker) -and
|
||||
$_ -notmatch '^\s*127\.0\.0\.1\s+185\.207\.214\.85' })
|
||||
|
||||
Set-Content -LiteralPath $hosts -Encoding ASCII -Value ($content + "$line $marker")
|
||||
Write-Host ' Готово: 185.207.214.85 теперь указывает на 127.0.0.1.' -ForegroundColor Green
|
||||
Write-Host ' Запусти testserver\start.cmd, потом play.cmd -> 1 (с модами).'
|
||||
Write-Host ' Обратно: uninstall-hosts.ps1 (или netsh int ip reset).'
|
||||
@@ -0,0 +1,188 @@
|
||||
# Installs the modloader: copies the runtime files, patches the launcher and
|
||||
# wires the agent into the launcher config.
|
||||
#
|
||||
# install.cmd normal install
|
||||
# install.cmd --uninstall put everything back
|
||||
# install.cmd --home <path> install the runtime somewhere else
|
||||
# install.cmd --game <path> point at a specific game installation
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$Repo = Split-Path -Parent $PSScriptRoot
|
||||
if (-not $Repo) { $Repo = $PSCommandPath | Split-Path -Parent | Split-Path -Parent }
|
||||
|
||||
$LauncherHome = Join-Path $env:APPDATA 'kjstudio\launcher'
|
||||
$Config = Join-Path $LauncherHome 'launcher_config.properties'
|
||||
$AppJar = Join-Path $LauncherHome 'app.jar'
|
||||
$Marker = Join-Path $LauncherHome '.rsx-patched'
|
||||
$Dist = Join-Path $Repo 'dist'
|
||||
$ModHome = Join-Path $env:LOCALAPPDATA 'rsx-mod'
|
||||
$GamePath = $null
|
||||
$Uninstall = $false
|
||||
|
||||
for ($i = 0; $i -lt $args.Count; $i++) {
|
||||
switch ($args[$i]) {
|
||||
'--uninstall' { $Uninstall = $true }
|
||||
'--home' { $ModHome = $args[++$i] }
|
||||
'--game' { $GamePath = $args[++$i] }
|
||||
default { }
|
||||
}
|
||||
}
|
||||
|
||||
function Say($text, $color) {
|
||||
if ($color) { Write-Host " $text" -ForegroundColor $color } else { Write-Host " $text" }
|
||||
}
|
||||
function Die($text) { Say $text Red; exit 1 }
|
||||
|
||||
# --------------------------------------------------------------- launcher must be closed
|
||||
function Get-LauncherRunning {
|
||||
Get-Process -ErrorAction SilentlyContinue | Where-Object {
|
||||
$_.MainWindowTitle -like '*Koptojop*' -or
|
||||
($_.Path -and $_.Path -like "$LauncherHome*")
|
||||
}
|
||||
}
|
||||
|
||||
$running = Get-LauncherRunning
|
||||
if ($running) {
|
||||
Die 'Лаунчер запущен - закрой его (крестик) и запусти установщик снова.'
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------- java and patcher
|
||||
$FindPatcher = Join-Path $Dist 'rsx-launcher-patch.jar'
|
||||
|
||||
function Find-Java {
|
||||
$candidates = @(
|
||||
(Join-Path $LauncherHome 'runtime\java\bin\java.exe')
|
||||
)
|
||||
foreach ($c in $candidates) {
|
||||
if (Test-Path $c) { return $c }
|
||||
}
|
||||
$cmd = Get-Command java -ErrorAction SilentlyContinue
|
||||
if ($cmd) { return $cmd.Source }
|
||||
return $null
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------- read the config safely
|
||||
# Handing the config to java.util.Properties is the only safe way to read it: it
|
||||
# is a properties file, where a backslash escapes the next character.
|
||||
function Read-GamePath($java, $path, $patcher) {
|
||||
if (-not (Test-Path $path)) { return $null }
|
||||
$prev = $ErrorActionPreference
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$raw = & $java -jar $patcher getprop $path gamePath1 2>$null
|
||||
$ErrorActionPreference = $prev
|
||||
if ($raw) {
|
||||
$value = ($raw | Select-Object -First 1) -replace '^\s+', ''
|
||||
if ($value) { return $value }
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
if (-not (Test-Path $Config)) {
|
||||
Die "Не найден конфиг лаунчера: $Config"
|
||||
}
|
||||
|
||||
$game = Read-GamePath (Find-Java) $Config $FindPatcher
|
||||
if ($GamePath) { $game = $GamePath }
|
||||
|
||||
# --------------------------------------------------------------- uninstall
|
||||
if ($Uninstall) {
|
||||
Say 'Удаляю модлоадер...'
|
||||
$backup = "$AppJar.orig"
|
||||
if (Test-Path $backup) {
|
||||
Copy-Item $backup $AppJar -Force
|
||||
Say 'app.jar восстановлен из резервной копии'
|
||||
} else {
|
||||
Say 'резервной копии нет, лаунчер не трогаю'
|
||||
}
|
||||
$ErrorActionPreference = 'Continue'
|
||||
& $java -jar $FindPatcher setenv $Config '' 2>&1 |
|
||||
ForEach-Object { Say $_ }
|
||||
$ErrorActionPreference = 'Stop'
|
||||
Say 'env убран из конфига лаунчера'
|
||||
Remove-Item $Marker -Force -ErrorAction SilentlyContinue
|
||||
Say 'маркер удалён'
|
||||
Say 'Готово. Лаунчер снова запускается как обычно.' Green
|
||||
exit 0
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------- checks
|
||||
if (-not (Test-Path $Dist)) { Die "Нет каталога dist: $Dist (собери через build.cmd)" }
|
||||
foreach ($f in 'rsx-bridge.jar', 'rsx-launcher-patch.jar', 'rsx-api.jar') {
|
||||
if (-not (Test-Path (Join-Path $Dist $f))) { Die "Нет dist\$f - запусти build.cmd" }
|
||||
}
|
||||
$java = Find-Java
|
||||
if (-not $java) { Die 'Не найден java (нужен лаунчерный runtime или java в PATH)' }
|
||||
|
||||
# a clean base to patch: re-patching an already patched jar is a no-op
|
||||
if (Test-Path "$AppJar.orig") {
|
||||
Copy-Item "$AppJar.orig" $AppJar -Force
|
||||
Say 'восстановлен оригинальный app.jar перед патчем'
|
||||
}
|
||||
|
||||
Say "Лаунчер: $LauncherHome"
|
||||
Say "Игра: $(if ($game) { $game } else { 'не указан в gamePath1' })"
|
||||
Say "Модлоадер: $ModHome"
|
||||
Say ''
|
||||
|
||||
# --------------------------------------------------------------- copy the runtime
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $ModHome 'bridge\profiles') | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $ModHome 'mods') | Out-Null
|
||||
Copy-Item (Join-Path $Dist 'rsx-bridge.jar') (Join-Path $ModHome 'bridge') -Force
|
||||
Say 'скопирован rsx-bridge.jar'
|
||||
|
||||
$existingProfile = Join-Path $ModHome 'bridge\profiles\latest.rsxp'
|
||||
$oldProfile = 'G:\rsx-mod\bridge\profiles\latest.rsxp'
|
||||
if (-not (Test-Path $existingProfile) -and (Test-Path $oldProfile)) {
|
||||
Copy-Item $oldProfile (Split-Path $existingProfile) -Force
|
||||
Say 'перенесён профиль сборки игры (latest.rsxp)'
|
||||
} elseif (Test-Path $existingProfile) {
|
||||
Say 'профиль уже на месте, оставляю как есть'
|
||||
} else {
|
||||
Say 'профиля нет - запусти prepare-build.cmd после первой установки', Yellow
|
||||
}
|
||||
|
||||
# --------------------------------------------------------------- patch the launcher
|
||||
Say ''
|
||||
Say 'Патчу лаунчер...'
|
||||
$patcher = Join-Path $Dist 'rsx-launcher-patch.jar'
|
||||
$meta = "wa`nALLATORIxDEMO"
|
||||
# native stderr must not be treated as a PowerShell error here
|
||||
$prev = $ErrorActionPreference
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$out = & $java -jar $patcher patch $AppJar $ModHome $meta 2>&1
|
||||
$code = $LASTEXITCODE
|
||||
$ErrorActionPreference = $prev
|
||||
$out | ForEach-Object { Say $_ }
|
||||
if ($code -ne 0) {
|
||||
Die "Патч не удался (код $code). Если лаунчер запущен с правами администратора - закрой его и повтори."
|
||||
}
|
||||
|
||||
Set-Content -LiteralPath $Marker -Value 'patched app.jar: rsx modloader' -Encoding ASCII
|
||||
Say 'маркер .rsx-patched создан'
|
||||
|
||||
# --------------------------------------------------------------- wire the agent
|
||||
$agentArg = "-javaagent:`"$ModHome\bridge\rsx-bridge.jar`""
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$out = & $java -jar $patcher setenv $Config $agentArg 2>&1
|
||||
$code = $LASTEXITCODE
|
||||
$ErrorActionPreference = $prev
|
||||
$out | ForEach-Object { Say $_ }
|
||||
if ($code -ne 0) {
|
||||
Die "Не удалось записать env в конфиг лаунчера (код $code)"
|
||||
}
|
||||
|
||||
Say ''
|
||||
Say 'Проверяю, что путь читается как надо...'
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$check = & $java -jar $patcher showenv $Config 2>&1
|
||||
$ErrorActionPreference = $prev
|
||||
$check | ForEach-Object { Say $_ }
|
||||
|
||||
Say ''
|
||||
Say 'Готово.' Green
|
||||
Say ''
|
||||
Say 'Дальше:'
|
||||
Say ' 1. запускай лаунчер через start-launcher.cmd, а не ярлыком -'
|
||||
Say ' updater.exe перекачает app.jar и сотрёт патч'
|
||||
Say ' 2. жми «Играть» - появится выбор «С модами / Ванилла»'
|
||||
Say " 3. моды клади в $ModHome\mods"
|
||||
@@ -0,0 +1,41 @@
|
||||
# Starts the patched launcher directly, without updater.exe.
|
||||
#
|
||||
# updater.exe re-downloads app.jar whenever its hash differs from the
|
||||
# manifest, which is exactly what a patched jar looks like - so launching
|
||||
# through the desktop shortcut silently undoes the patch. This runs the
|
||||
# launcher itself, with the JavaFX runtime that ships next to it.
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$LauncherHome = Join-Path $env:APPDATA 'kjstudio\launcher'
|
||||
$Java = Join-Path $LauncherHome 'runtime\java\bin\javaw.exe'
|
||||
$Jar = Join-Path $LauncherHome 'app.jar'
|
||||
$FxLib = Join-Path $LauncherHome 'runtime\javafx\lib'
|
||||
$FxBin = Join-Path $LauncherHome 'runtime\javafx\bin'
|
||||
|
||||
if (-not (Test-Path $Java) -or -not (Test-Path $Jar)) {
|
||||
Write-Host " Нет лаунчера: $Jar" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Remove-Item (Join-Path $LauncherHome 'app.lock') -Force -ErrorAction SilentlyContinue
|
||||
|
||||
$env:JAVA_TOOL_OPTIONS = ''
|
||||
Write-Host ' Запускаю лаунчер напрямую (без updater.exe)...'
|
||||
Start-Process -FilePath $Java -ArgumentList @(
|
||||
'--module-path', "`"$FxLib`"",
|
||||
'--add-modules', 'ALL-MODULE-PATH',
|
||||
"-Djava.library.path=`"$FxBin`"",
|
||||
'-Dprism.order=sw',
|
||||
'-cp', "`"$Jar`"",
|
||||
'application.Main'
|
||||
) -WorkingDirectory $LauncherHome | Out-Null
|
||||
|
||||
Start-Sleep -Seconds 12
|
||||
$up = Get-Process -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.MainWindowTitle -like '*Koptojop*' }
|
||||
if ($up) {
|
||||
Write-Host ' Лаунчер запущен, окно должно появиться.' -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host ' Лаунчер не поднялся, смотри logs в папке лаунчера.' -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
# Removes the hosts entry added by install-hosts.ps1.
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$hosts = Join-Path $env:SystemRoot 'System32\drivers\etc\hosts'
|
||||
$marker = '# rsx modloader test server'
|
||||
|
||||
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$isAdmin = (New-Object Security.Principal.WindowsPrincipal($id)).IsInRole(
|
||||
[Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
if (-not $isAdmin) {
|
||||
Write-Host ' Нужны права администратора: запусти PowerShell от администратора.' -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
$content = @(Get-Content -LiteralPath $hosts |
|
||||
Where-Object { $_ -notmatch [regex]::Escape($marker) -and
|
||||
$_ -notmatch '^\s*127\.0\.0\.1\s+185\.207\.214\.85' })
|
||||
|
||||
Set-Content -LiteralPath $hosts -Encoding ASCII -Value $content
|
||||
Write-Host ' Запись удалена, клиент снова ходит на официальный сервер.' -ForegroundColor Green
|
||||
Reference in New Issue
Block a user