clean up installation script, remove unnecessary big VDF parser

This commit is contained in:
Jonny_Bro (Nikita) 2024-07-20 01:15:04 +05:00
parent d63649e354
commit ea9b5b173f
No known key found for this signature in database
GPG key ID: 3F1ECC04147E9BD8

View file

@ -1,345 +1,89 @@
# VDF Deserializer
# Function to query the registry
function Get-RegistryValue {
param (
[string]$path,
[string]$value
)
Enum State
{
Start = 0;
Property = 1;
Object = 2;
Conditional = 3;
Finished = 4;
Closed = 5
};
Class VdfDeserializer
{
[PSCustomObject] Deserialize([string]$vdfContent)
{
if([string]::IsNullOrWhiteSpace($vdfContent)) {
throw 'Mandatory argument $vdfContent must be a non-empty, non-whitespace object of type [string]';
}
[System.IO.TextReader]$reader = [System.IO.StringReader]::new($vdfContent);
return $this.Deserialize($reader);
}
[PSCustomObject] Deserialize([System.IO.TextReader]$txtReader)
{
if( !$txtReader ){
throw 'Mandatory arguments $textReader missing.';
}
$vdfReader = [VdfTextReader]::new($txtReader);
$result = [PSCustomObject]@{ };
try
{
if (!$vdfReader.ReadToken())
{
throw "Incomplete VDF data.";
}
$prop = $this.ReadProperty($vdfReader);
Add-Member -InputObject $result -MemberType NoteProperty -Name $prop.Key -Value $prop.Value;
}
finally
{
if($vdfReader)
{
$vdfReader.Close();
}
}
return $result;
}
[hashtable] ReadProperty([VdfTextReader]$vdfReader)
{
$key=$vdfReader.Value;
if (!$vdfReader.ReadToken())
{
throw "Incomplete VDF data.";
}
if ($vdfReader.CurrentState -eq [State]::Property)
{
$result = @{
Key = $key;
Value = $vdfReader.Value;
}
}
else
{
$result = @{
Key = $key;
Value = $this.ReadObject($vdfReader);
}
}
return $result;
}
[PSCustomObject] ReadObject([VdfTextReader]$vdfReader)
{
$result = [PSCustomObject]@{ };
if (!$vdfReader.ReadToken())
{
throw "Incomplete VDF data.";
}
while ( ($vdfReader.CurrentState -ne [State]::Object) -or ($vdfReader.Value -ne "}"))
{
[hashtable]$prop = $this.ReadProperty($vdfReader);
Add-Member -InputObject $result -MemberType NoteProperty -Name $prop.Key -Value $prop.Value;
if (!$vdfReader.ReadToken())
{
throw "Incomplete VDF data.";
}
}
return $result;
try {
$result = Get-ItemProperty -Path $path -ErrorAction Stop
return $result.$value
} catch {
return $null
}
}
Class VdfTextReader
{
[string]$Value;
[State]$CurrentState;
# Get Steam installation path from registry
$steam_dir = Get-RegistryValue "HKLM:\SOFTWARE\Valve\Steam" "InstallPath"
hidden [ValidateNotNull()][System.IO.TextReader]$_reader;
if (-not $steam_dir) {
$steam_dir = Get-RegistryValue "HKLM:\SOFTWARE\WOW6432Node\Valve\Steam" "InstallPath"
}
hidden [ValidateNotNull()][char[]]$_charBuffer=;
hidden [ValidateNotNull()][char[]]$_tokenBuffer=;
if (-not $steam_dir) {
Write-Host "Steam installation path not found"
Read-Host "Press Enter to exit"
exit
}
hidden [int32]$_charPos;
hidden [int32]$_charsLen;
hidden [int32]$_tokensize;
hidden [bool]$_isQuoted;
# Check for Garry's Mod installation
$gmod_dir = Join-Path $steam_dir "steamapps\common\GarrysMod"
if (-not (Test-Path (Join-Path $steam_dir "steamapps\appmanifest_4000.acf"))) {
$library_folders_path = Join-Path $steam_dir "steamapps\libraryfolders.vdf"
VdfTextReader([System.IO.TextReader]$txtReader)
{
if( !$txtReader ){
throw "Mandatory arguments `$textReader missing.";
}
$this._reader = $txtReader;
$this._charBuffer=[char[]]::new(1024);
$this._tokenBuffer=[char[]]::new(4096);
$this._charPos=0;
$this._charsLen=0;
$this._tokensize=0;
$this._isQuoted=$false;
$this.Value="";
$this.CurrentState=[State]::Start;
}
[bool] ReadToken()
{
if (!$this.SeekToken())
{
return $false;
}
$this._tokenSize = 0;
while($this.EnsureBuffer())
{
[char]$curChar = $this._charBuffer[$this._charPos];
#No special treatment for escape characters
#region Quote
if ($curChar -eq '"' -or (!$this._isQuoted -and [Char]::IsWhiteSpace($curChar)))
{
$this.Value = [string]::new($this._tokenBuffer, 0, $this._tokenSize);
$this.CurrentState = [State]::Property;
$this._charPos++;
return $true;
}
#endregion Quote
#region Object Start/End
if (($curChar -eq '{') -or ($curChar -eq '}'))
{
if ($this._isQuoted)
{
$this._tokenBuffer[$this._tokenSize++] = $curChar;
$this._charPos++;
continue;
}
elseif ($this._tokenSize -ne 0)
{
$this.Value = [string]::new($this._tokenBuffer, 0, $this._tokenSize);
$this.CurrentState = [State]::Property;
return $true;
}
else
{
$this.Value = $curChar.ToString();
$this.CurrentState = [State]::Object;
$this._charPos++;
return $true;
if (Test-Path $library_folders_path) {
$lines = Get-Content $library_folders_path
foreach ($line in $lines) {
if ($line -match '^\s*"\d+"\s+"(.+)"$') {
$library_path = $matches[1]
if (Test-Path (Join-Path $library_path "steamapps\appmanifest_4000.acf")) {
$gmod_dir = Join-Path $library_path "steamapps\common\GarrysMod"
break
}
}
#endregion Object Start/End
#region Long Token
$this._tokenBuffer[$this._tokenSize++] = $curChar;
$this._charPos++;
#endregion Long Token
}
return $false;
}
[void] Close()
{
$this.CurrentState = [State]::Closed;
}
hidden [bool] SeekToken()
{
while($this.EnsureBuffer())
{
# Skip Whitespace
if( [char]::IsWhiteSpace($this._charBuffer[$this._charPos]) )
{
$this._charPos++;
continue;
}
# Token
if ($this._charBuffer[$this._charPos] -eq '"')
{
$this._isQuoted = $true;
$this._charPos++;
return $true;
}
# Comment
if ($this._charBuffer[$this._charPos] -eq '/')
{
$this.SeekNewLine();
$this._charPos++;
continue;
}
$this._isQuoted = $false;
return $true;
}
return $false;
}
hidden [bool] SeekNewLine()
{
while ($this.EnsureBuffer())
{
if ($this._charBuffer[++$this._charPos] == '\n')
{
return $true;
}
}
return $false;
}
hidden [bool]EnsureBuffer()
{
if($this._charPos -lt $this._charsLen -1)
{
return $true;
}
[int32] $remainingChars = $this._charsLen - $this._charPos;
$this._charBuffer[0] = $this._charBuffer[($this._charsLen - 1) * $remainingChars]; #A bit of mathgic to improve performance by avoiding a conditional.;
$this._charsLen = $this._reader.Read($this._charBuffer, $remainingChars, 1024 - $remainingChars) + $remainingChars;
$this._charPos = 0;
return ($this._charsLen -ne 0);
}
}
function GetCount($thing) {
$aux = $($thing | Get-Member -MemberType NoteProperty);
$count = 0;
if ($null -eq $aux) {
$count = 0;
} elseif ( $aux -is [PSCustomObject] ) {
$count = 1;
} else {
$count = $aux.Count;
}
return $count;
if (-not (Test-Path $gmod_dir)) {
Write-Host "GMod installation path not found"
Read-Host "Press Enter to exit"
exit
}
$VDF = [VdfDeserializer]::new();
Write-Host "GMod installation path: $gmod_dir"
# Main Script
# Confirm Garry's Mod installation path
$GMODPath = Join-Path $gmod_dir "garrysmod"
$AddonsPath = Join-Path $GMODPath "addons"
$_text = "Do you want to install in this path? It will completely wipe the previous Beatrun install if you had one!`n$GMODPath (y/n)"
$GMODConfirmation = Read-Host $_text
$SteamPath = Get-ItemProperty -Path HKLM:/SOFTWARE/WOW6432Node/Valve/Steam;
$SteamPath = $SteamPath.InstallPath;
$SteamPath = $SteamPath.ToString();
Write-Host Looking for Steam libraries...;
$LibraryFoldersVDF = $SteamPath + "/steamapps/libraryfolders.vdf";
$LibrariesRaw = Get-Content $LibraryFoldersVDF;
$LibrariesVDF = $VDF.Deserialize($LibrariesRaw);
Write-Host Found!;
$libcount = GetCount($LibrariesVDF.libraryfolders);
for ($i = 0; $i -lt $libcount; $i++) {
$Install = $LibrariesVDF.libraryfolders.$i;
$GMODInstalled = $Install.apps.4000;
if ($GMODInstalled) {
$GMODPath = $Install.path + "\\steamapps\\common\\GarrysMod";
$AddonsPath = $GMODPath + "\\garrysmod\\addons";
$_text = "Do you want to install in this path? It will completely wipe the previous Beatrun install if you had one! `n" + $GMODPath.replace("\\", "\") + " (y/n)";
$GMODConfirmation = Read-Host $_text;
if ($GMODConfirmation -eq "y") {
$TempPath = $GMODPath + "\\temp\\";
$ZIPPath = $TempPath + "beatrun.zip";
$FolderPath = $TempPath + "beatrun";
$FolderMainPath = $TempPath + "beatrun-main";
(New-Item -ItemType Directory -Path $TempPath) | out-null;
Write-Host Downloading the archive...;
(New-Object Net.WebClient).DownloadFile("https://github.com/JonnyBro/beatrun/archive/refs/heads/main.zip", $ZIPPath);
Write-Host Downloaded! Unpacking...;
Expand-Archive $ZIPPath $TempPath -Force;
Write-Host Unpacked successfully!;
Rename-Item $FolderMainPath $FolderPath;
Remove-Item $ZIPPath;
$confirmation = Read-Host "Do you want to install modules? (Discord + Steam Presence) (y/n)";
if ($GMODConfirmation -eq "y") {
$TempPath = Join-Path $GMODPath "temp"
$ZIPPath = Join-Path $TempPath "beatrun.zip"
$FolderPath = Join-Path $TempPath "beatrun"
$FolderMainPath = Join-Path $TempPath "beatrun-main"
New-Item -ItemType Directory -Path $TempPath -Force | Out-Null
Write-Host "Downloading the archive..."
(New-Object Net.WebClient).DownloadFile("https://github.com/JonnyBro/beatrun/archive/refs/heads/main.zip", $ZIPPath)
Write-Host "Downloaded! Unpacking..."
Expand-Archive $ZIPPath $TempPath -Force
Write-Host "Unpacked successfully!"
Rename-Item $FolderMainPath $FolderPath
Remove-Item $ZIPPath
$confirmation = Read-Host "Do you want to install modules? (Discord + Steam Presence) (y/n)"
if ($confirmation -eq "y") {
$ModulesPath = $FolderPath + "\\lua\\*";
$NewModulesPath = $GMODPath + "\\garrysmod\\lua\\";
Copy-Item -Path $ModulesPath -Destination $NewModulesPath -Force -Recurse;
}
$AddonPath = $FolderPath + "\\beatrun";
$NewAddonPath = $AddonsPath + "\\beatrun";
if ((Test-Path $NewAddonPath) -eq $true) {
Remove-Item $NewAddonPath -Force -Recurse;
}
Move-Item -Path $AddonPath -Destination $NewAddonPath;
Remove-Item $TempPath -Force -Recurse;
Write-Host Beatrun Installed!;
$ModulesPath = Join-Path $FolderPath "lua\*"
$NewModulesPath = Join-Path $GMODPath "lua"
Copy-Item -Path $ModulesPath -Destination $NewModulesPath -Force -Recurse
}
$AddonPath = Join-Path $FolderPath "beatrun"
$NewAddonPath = Join-Path $AddonsPath "beatrun"
if (Test-Path $NewAddonPath) {
Remove-Item $NewAddonPath -Force -Recurse
}
Move-Item -Path $AddonPath -Destination $NewAddonPath
Remove-Item $TempPath -Force -Recurse
Write-Host "Beatrun Installed!"
}