mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-25 23:18:44 -07:00
4034449a6d
- Removed Photon configuration fields from dorknet-clientmod.json.template. - Added new backtrace and Azure Speech configuration endpoints in ConfigController. - Updated response format for IsCreationEnabled and IsRenderingEnabled endpoints in CustomAvatarItemsController. - Enhanced InfluencerPartnerProgramController to include additional player properties. - Implemented RoomKeepsakes endpoint in KeepsakesController to retrieve keepsakes by room ID. - Modified ReportsController to standardize response for Hile reporting. - Added PlayerDataForMe and RoomsRequiring endpoints in RoomsController for enhanced player data retrieval. - Introduced new dorm matchmaking methods in MatchController for player session management. - Updated MatchPlayerController to handle exclusive login functionality. - Revised install scripts to reflect changes in Photon AppId handling and patching process. - Added new patch-client.ps1 script for applying static byte patches to the Rec Room client.
265 lines
9.0 KiB
PowerShell
265 lines
9.0 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Applies static DorkNet byte patches to an extracted Rec Room client.
|
|
|
|
.DESCRIPTION
|
|
RecRoomPath must point at the Unity data folder, usually
|
|
Recroom_Release_Data or RecRoom_Data. The script resolves the install root
|
|
from that folder, then patches the hardcoded Photon Realtime and Voice
|
|
AppIds wherever the build stores them: GameAssembly.dll,
|
|
il2cpp_data\Metadata\global-metadata.dat, and resources.assets.
|
|
|
|
The replacement values must be GUID strings, so the byte length stays
|
|
unchanged and the patch can be done in place.
|
|
|
|
.PARAMETER RecRoomPath
|
|
Path to Recroom_Release_Data.
|
|
|
|
.PARAMETER PhotonAppId
|
|
Photon Cloud Realtime AppId.
|
|
|
|
.PARAMETER PhotonVoiceAppId
|
|
Photon Cloud Voice AppId. Defaults to PhotonAppId.
|
|
|
|
.PARAMETER DisableSignatureChecks
|
|
Deprecated compatibility switch. File-check bypass is handled by
|
|
DorkNet.ClientMod so the embedded build/signature identifiers stay valid.
|
|
|
|
.PARAMETER Revert
|
|
Restore patched files from backups created by this script.
|
|
|
|
.PARAMETER DryRun
|
|
Show what would be patched without writing files.
|
|
#>
|
|
|
|
[CmdletBinding(DefaultParameterSetName = 'Patch')]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$RecRoomPath,
|
|
|
|
[Parameter(Mandatory = $true, ParameterSetName = 'Patch')]
|
|
[ValidatePattern('(?i)^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$')]
|
|
[string]$PhotonAppId,
|
|
|
|
[Parameter(ParameterSetName = 'Patch')]
|
|
[ValidatePattern('(?i)^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$')]
|
|
[string]$PhotonVoiceAppId,
|
|
|
|
[Parameter(ParameterSetName = 'Patch')]
|
|
[switch]$DisableSignatureChecks,
|
|
|
|
[Parameter(ParameterSetName = 'Patch')]
|
|
[string]$ImageSigningPublicKeyPath,
|
|
|
|
[Parameter(ParameterSetName = 'Patch')]
|
|
[string]$ServerIp,
|
|
|
|
[Parameter(ParameterSetName = 'Patch')]
|
|
[string]$CertPath,
|
|
|
|
[Parameter(Mandatory = $true, ParameterSetName = 'Revert')]
|
|
[switch]$Revert,
|
|
|
|
[switch]$DryRun
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
Set-StrictMode -Version Latest
|
|
|
|
$OfficialPhotonAppId = '9372aa8d-d3f4-44a0-986d-419e145a2b83'
|
|
$OfficialPhotonVoiceAppId = 'e93ae440-f238-4b6c-848f-1df89faf14f5'
|
|
|
|
function Write-Step($msg) { Write-Host ('> ' + $msg) -ForegroundColor Cyan }
|
|
function Write-OK($msg) { Write-Host ('OK: ' + $msg) -ForegroundColor Green }
|
|
function Write-Warn($msg) { Write-Host ('WARN: ' + $msg) -ForegroundColor Yellow }
|
|
|
|
function Find-SequenceOffsets {
|
|
param(
|
|
[Parameter(Mandatory = $true)][byte[]]$Haystack,
|
|
[Parameter(Mandatory = $true)][byte[]]$Needle
|
|
)
|
|
|
|
$offsets = New-Object System.Collections.Generic.List[int]
|
|
if ($Needle.Length -eq 0 -or $Haystack.Length -lt $Needle.Length) {
|
|
return $offsets
|
|
}
|
|
|
|
$last = $Haystack.Length - $Needle.Length
|
|
for ($i = 0; $i -le $last; $i++) {
|
|
if ($Haystack[$i] -ne $Needle[0]) { continue }
|
|
$matched = $true
|
|
for ($j = 1; $j -lt $Needle.Length; $j++) {
|
|
if ($Haystack[$i + $j] -ne $Needle[$j]) {
|
|
$matched = $false
|
|
break
|
|
}
|
|
}
|
|
if ($matched) { $offsets.Add($i) }
|
|
}
|
|
return $offsets
|
|
}
|
|
|
|
function Format-HexOffset([int]$Offset) {
|
|
return '0x{0:X}' -f $Offset
|
|
}
|
|
|
|
function Apply-AsciiStringPatch {
|
|
param(
|
|
[Parameter(Mandatory = $true)][byte[]]$Bytes,
|
|
[Parameter(Mandatory = $true)][string]$Original,
|
|
[Parameter(Mandatory = $true)][string]$Replacement,
|
|
[Parameter(Mandatory = $true)][string]$Label
|
|
)
|
|
|
|
$enc = [System.Text.Encoding]::ASCII
|
|
$originalBytes = $enc.GetBytes($Original)
|
|
$replacementBytes = $enc.GetBytes($Replacement)
|
|
if ($originalBytes.Length -ne $replacementBytes.Length) {
|
|
throw "$Label replacement length differs from original. Expected $($originalBytes.Length) bytes, got $($replacementBytes.Length)."
|
|
}
|
|
|
|
$offsets = @(Find-SequenceOffsets -Haystack $Bytes -Needle $originalBytes)
|
|
if ($offsets.Count -eq 0) {
|
|
$replacementOffsets = @(Find-SequenceOffsets -Haystack $Bytes -Needle $replacementBytes)
|
|
if ($replacementOffsets.Count -gt 0) {
|
|
Write-OK "$Label already patched at $((@($replacementOffsets) | ForEach-Object { Format-HexOffset $_ }) -join ', ')"
|
|
return $false
|
|
}
|
|
Write-Warn "$Label official AppId '$Original' was not found, and replacement '$Replacement' is not already present."
|
|
return $null
|
|
}
|
|
|
|
foreach ($offset in $offsets) {
|
|
[System.Array]::Copy($replacementBytes, 0, $Bytes, $offset, $replacementBytes.Length)
|
|
}
|
|
Write-OK "$Label patched at $((@($offsets) | ForEach-Object { Format-HexOffset $_ }) -join ', ')"
|
|
return $true
|
|
}
|
|
|
|
function Get-ClientPaths {
|
|
param([Parameter(Mandatory = $true)][string]$Path)
|
|
|
|
$resolved = Resolve-Path -LiteralPath $Path -ErrorAction SilentlyContinue
|
|
if (-not $resolved) {
|
|
throw "RecRoomPath '$Path' does not exist."
|
|
}
|
|
|
|
$dataPath = $resolved.Path
|
|
if (-not (Test-Path -LiteralPath (Join-Path $dataPath 'resources.assets') -PathType Leaf)) {
|
|
throw "resources.assets not found in '$dataPath'. Point RecRoomPath at the Recroom_Release_Data folder."
|
|
}
|
|
|
|
$root = Split-Path -Parent $dataPath
|
|
$gameAssembly = Join-Path $root 'GameAssembly.dll'
|
|
if (-not (Test-Path -LiteralPath $gameAssembly -PathType Leaf)) {
|
|
throw "GameAssembly.dll not found next to '$dataPath'."
|
|
}
|
|
|
|
[pscustomobject]@{
|
|
DataPath = $dataPath
|
|
Root = $root
|
|
GameAssembly = $gameAssembly
|
|
Resources = Join-Path $dataPath 'resources.assets'
|
|
GlobalMetadata = Join-Path $dataPath 'il2cpp_data\Metadata\global-metadata.dat'
|
|
}
|
|
}
|
|
|
|
$paths = Get-ClientPaths -Path $RecRoomPath
|
|
$patchTargets = @(
|
|
[pscustomobject]@{ Label = 'GameAssembly.dll'; Path = $paths.GameAssembly },
|
|
[pscustomobject]@{ Label = 'global-metadata.dat'; Path = $paths.GlobalMetadata },
|
|
[pscustomobject]@{ Label = 'resources.assets'; Path = $paths.Resources }
|
|
) | Where-Object { Test-Path -LiteralPath $_.Path -PathType Leaf }
|
|
|
|
if ($Revert) {
|
|
$restored = 0
|
|
foreach ($target in $patchTargets) {
|
|
$backup = "$($target.Path).dorknet-appid-backup"
|
|
if (-not (Test-Path -LiteralPath $backup -PathType Leaf)) {
|
|
continue
|
|
}
|
|
Write-Step "Reverting $($target.Label) from $backup"
|
|
if ($DryRun) {
|
|
Write-Host "DRY RUN: would restore $($target.Path) from $backup"
|
|
$restored++
|
|
continue
|
|
}
|
|
Copy-Item -LiteralPath $backup -Destination $target.Path -Force
|
|
Write-OK "$($target.Label) restored."
|
|
$restored++
|
|
}
|
|
if ($restored -eq 0) {
|
|
throw "No DorkNet AppId backups found under $($paths.Root)."
|
|
}
|
|
exit 0
|
|
}
|
|
|
|
if (-not $PhotonVoiceAppId) {
|
|
$PhotonVoiceAppId = $PhotonAppId
|
|
}
|
|
|
|
if ($ImageSigningPublicKeyPath) {
|
|
Write-Warn 'ImageSigningPublicKeyPath is accepted for installer compatibility, but this patcher currently only applies Photon AppId byte patches.'
|
|
}
|
|
if ($ServerIp -or $CertPath) {
|
|
Write-Warn 'ServerIp/CertPath are accepted for legacy installer compatibility, but hosts/cert patching is not applied by this script.'
|
|
}
|
|
if ($DisableSignatureChecks) {
|
|
Write-Warn 'DisableSignatureChecks is handled by DorkNet.ClientMod; no signature metadata bytepatch is applied.'
|
|
}
|
|
|
|
if ($patchTargets.Count -eq 0) {
|
|
throw "No patchable client files found under $($paths.Root)."
|
|
}
|
|
|
|
$anyChanged = $false
|
|
$anyFound = $false
|
|
foreach ($target in $patchTargets) {
|
|
Write-Step "Patching Photon AppIds in $($target.Path)"
|
|
$bytes = [System.IO.File]::ReadAllBytes($target.Path)
|
|
$fileChanged = $false
|
|
|
|
$realtimeResult = Apply-AsciiStringPatch -Bytes $bytes -Original $OfficialPhotonAppId -Replacement $PhotonAppId.ToLowerInvariant() -Label "$($target.Label) Photon Realtime AppId"
|
|
if ($null -ne $realtimeResult) {
|
|
$anyFound = $true
|
|
$fileChanged = $realtimeResult -or $fileChanged
|
|
}
|
|
|
|
$voiceResult = Apply-AsciiStringPatch -Bytes $bytes -Original $OfficialPhotonVoiceAppId -Replacement $PhotonVoiceAppId.ToLowerInvariant() -Label "$($target.Label) Photon Voice AppId"
|
|
if ($null -ne $voiceResult) {
|
|
$anyFound = $true
|
|
$fileChanged = $voiceResult -or $fileChanged
|
|
}
|
|
|
|
if (-not $fileChanged) {
|
|
Write-OK "No $($target.Label) changes needed."
|
|
continue
|
|
}
|
|
|
|
$anyChanged = $true
|
|
$backup = "$($target.Path).dorknet-appid-backup"
|
|
if ($DryRun) {
|
|
Write-Host "DRY RUN: would write patched $($target.Label)"
|
|
if (-not (Test-Path -LiteralPath $backup -PathType Leaf)) {
|
|
Write-Host "DRY RUN: would create backup $backup"
|
|
}
|
|
continue
|
|
}
|
|
|
|
if (-not (Test-Path -LiteralPath $backup -PathType Leaf)) {
|
|
Copy-Item -LiteralPath $target.Path -Destination $backup
|
|
Write-OK "Backup written to $backup"
|
|
}
|
|
|
|
[System.IO.File]::WriteAllBytes($target.Path, $bytes)
|
|
Write-OK "$($target.Label) Photon AppIds patched."
|
|
}
|
|
|
|
if (-not $anyFound) {
|
|
throw "Official Photon AppIds were not found in any patch target, and requested replacements were not already present."
|
|
}
|
|
|
|
if (-not $anyChanged) {
|
|
Write-OK 'No Photon AppId changes needed.'
|
|
}
|