Files
sasheg dev 450bdecc34 Клиент говорит с сервером по нашему протоколу
Раньше клиент умел только показывать меню. Теперь он заходит на сервер,
получает наш мир и рисует его.

Как это устроено:

- Наш сетевой слой (net/rustnotmc/client/net) читает наш протокол и
  переводит его пакеты в пакеты игры. Игра остаётся игрой: у неё есть
  мир, игрок, сущности и рендер, и все они работают. Не переписывать их
  ради того, чтобы нарисовать тот же мир иначе, незачем.
- Пакеты игры, которые не имеют соответствия у нас, не отправляются, а
  наоборот: перемещение игрока и ломание блока переводятся в наши.
- Экран входа игры (GuiConnecting) заменён наш: он спрашивает у лаунчера,
  кем пришёл игрок, и подставляет это в рукопожатие.
- Соединение качается из тика игры, а не из экрана. Рукопожатие, которое
  зависит от того, что экран ещё на экране, ломается alt-tab'ом.

Вход теперь через лаунчер, а не внутри игры:

- Лаунчер уже умеет логинить игрока и отдаёт игре имя, uuid и токен
  (--username, --uuid, --accessToken). Это та же роль, что у Yggdrasil в
  ванилле, только лаунчер наш.
- Сервер спрашивает лаунчер, один из ли наш этот игрок, и заодно получает
  бан-лист. Токен используется один раз и не хранится.
- Свои аккаунты сервера, когда настроен лаунчер, закрыты: сервер с двумя
  дверями не имеет дверей. Открыть их можно флагом, но намеренно.
- Если игру запустили без лаунчера, экран всё равно спрашивает имя и
  пароль: это путь для своего сервера и для разработки.

Проверено живьём: клиент вошёл по токену лаунчера, сервер спросил
лаунчер, лаунчер сказал "свой", игрок получил мир, 210 чанков пришли и
лежат на диске, рельеф нарисован.

Что чинилось по дороге:

- Minecraft.setIngameFocus() возвращал на главное меню, когда окно
  получало фокус. Игрок как раз кликает в окно, чтобы напечатать пароль, и
  экран входа исчезал в этот самый момент.
- Ответ лаунчера разбирается, а не ищется подстрокой: {"valid": true} и
  {"valid":true} это один и тот же ответ, и сервер, который понимает
  только второй, ломает работающий лаунчер.
2026-10-19 20:10:20 +03:00

70 lines
3.4 KiB
PowerShell

# Compiles the forked client from the existing sources. Fast iteration loop:
# fix, run this, look at the numbers. Use prepare-game.ps1 when the sources
# themselves need regenerating.
#
# ASCII only: PowerShell 5.1 reads a .ps1 without a byte order mark using the
# system ANSI code page.
$ErrorActionPreference = 'Stop'
$Fork = Split-Path -Parent $PSScriptRoot
if (-not $Fork) { $Fork = $PSCommandPath | Split-Path -Parent | Split-Path -Parent }
$Root = Split-Path -Parent $Fork
$Client = Join-Path $Root 'rsx-client'
$Astral = Join-Path $env:APPDATA 'AstralRinthApp\meta'
$Src = Join-Path $Fork 'src'
$Out = Join-Path $Fork 'build\classes'
$Temp = Join-Path $env:TEMP 'opencode'
Add-Type -AssemblyName System.IO.Compression.FileSystem
$good = New-Object System.Collections.Generic.List[string]
foreach ($j in (Get-ChildItem (Join-Path $Astral 'libraries') -Recurse -Filter '*.jar' -File)) {
if ($j.Length -le 100) { continue }
$ok = $false
try { $z = [System.IO.Compression.ZipFile]::OpenRead($j.FullName); $z.Dispose(); $ok = $true } catch { $ok = $false }
if ($ok) { $good.Add(($j.FullName -replace '\\', '/')) }
}
# The fork calls into the mod loader, so the loader has to be visible to javac
# exactly as it is at runtime. Building the loader first is what keeps the two
# from drifting apart.
$Loader = Join-Path $Client 'dist\rsx-loader.jar'
# The client speaks the server's own protocol, so the protocol and the account
# code are compiled against as well. They are the same jars the game runs with.
$Protocol = Join-Path $Root 'rsx-protocol\dist\rsx-protocol.jar'
$Auth = Join-Path $Root 'rsx-auth\dist\rsx-auth.jar'
$cp = @($good + $(if (Test-Path $Loader) { $Loader -replace '\\', '/' } else { $null }) `
+ $(if (Test-Path $Protocol) { $Protocol -replace '\\', '/' } else { $null }) `
+ $(if (Test-Path $Auth) { $Auth -replace '\\', '/' } else { $null })) -join ';'
$argf = Join-Path $Temp 'fork-build.txt'
$errf = Join-Path $Temp 'fork-build-errors.txt'
$sb = New-Object System.Text.StringBuilder
foreach ($a in @('-nowarn', '-proc:none', '-encoding', 'UTF-8', '--release', '17', '-d', ($Out -replace '\\', '/'))) { [void]$sb.AppendLine($a) }
[void]$sb.AppendLine('-cp'); [void]$sb.AppendLine('"' + $cp + '"')
Get-ChildItem $Src -Recurse -Filter '*.java' | ForEach-Object { [void]$sb.AppendLine(($_.FullName -replace '\\', '/')) }
Set-Content -LiteralPath $argf -Value $sb.ToString() -Encoding ASCII
Remove-Item $Out -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Force -Path $Out | Out-Null
$javac = (Get-Command javac).Source
& cmd /c "`"$javac`" @`"$argf`" -Xmaxerrs 10000 > `"$errf`" 2>&1"
$errors = Get-Content -LiteralPath $errf | Select-String -Pattern ': error:'
$classes = (Get-ChildItem $Out -Recurse -Filter '*.class' -File -ErrorAction SilentlyContinue).Count
if ($errors.Count -eq 0) {
Write-Host ''
Write-Host " FORK COMPILES CLEAN - $classes classes" -ForegroundColor Green
exit 0
}
$files = $errors | ForEach-Object { if ($_.Line -match '^([A-Z]:.*?\.java):\d+:') { $matches[1] } } | Sort-Object -Unique
Write-Host ''
Write-Host " $classes classes, $($errors.Count) errors in $($files.Count) files" -ForegroundColor Yellow
$errors | ForEach-Object { if ($_.Line -match '^([A-Z]:.*?\.java):\d+:') { $matches[1] } } |
Group-Object | Sort-Object Count -Descending | Select-Object -First 25 |
ForEach-Object { Write-Host (" {0,4} {1}" -f $_.Count, ($_.Name.Replace(($Src + '\'), ''))) -ForegroundColor Gray }