b8e5df778e
Моды грузятся через -javaagent, game.jar не патчится, переживают ре-обфускацию. Что внутри: - агент rsx-bridge.jar: профиль сборки игры, патчи A2/A6, загрузка модов через родной загрузчик игры (ilxq -> special.Main) - патч лаунчера: окно выбора «С модами / Ванилла» по кнопке «Играть» и защита от автоапдейта лаунчера - install/uninstall: всё ставится в %LOCALAPPDATA%\rsx-mod, пути не хардкодятся - build: три готовых артефакта в dist, нужен только JDK - testserver: локальный сервер, принимает любой ник и токен Проверено на живом клиенте: мод грузится и выполняется в игровом потоке, в логе видно игрока и мир.
188 lines
7.5 KiB
PowerShell
188 lines
7.5 KiB
PowerShell
# 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" |