clean up installation script, remove unnecessary big VDF parser
This commit is contained in:
parent
d63649e354
commit
ea9b5b173f
1 changed files with 76 additions and 332 deletions
408
static/install
408
static/install
|
@ -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;
|
||||
}
|
||||
|
||||
$VDF = [VdfDeserializer]::new();
|
||||
|
||||
# Main Script
|
||||
|
||||
$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 ($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!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not (Test-Path $gmod_dir)) {
|
||||
Write-Host "GMod installation path not found"
|
||||
Read-Host "Press Enter to exit"
|
||||
exit
|
||||
}
|
||||
|
||||
Write-Host "GMod installation path: $gmod_dir"
|
||||
|
||||
# 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
|
||||
|
||||
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 = 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!"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue