-
Notifications
You must be signed in to change notification settings - Fork 170
/
Steam.ps1
331 lines (288 loc) · 13.4 KB
/
Steam.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
param (
[Parameter(Mandatory=$true)][string]$game_name,
[Parameter(Mandatory=$true)][string]$dotnet,
[Parameter(Mandatory=$true)][string]$target_dir,
[Parameter(Mandatory=$true)][string]$managed_dir,
[string]$platform = "windows",
[string]$deobfuscator = "",
[string]$steam_appid = "0",
[string]$steam_branch = "public",
[string]$steam_depot = "",
[string]$steam_access = "anonymous",
[string]$references_override = ""
)
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# Check PowerShell version
$ps_version = $PSVersionTable.PSVersion.Major
if ($ps_version -le 5)
{
Write-Host "Error: PowerShell version 6 or higher required to continue, $ps_version currently installed"
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
exit 1
}
# Format project name and set depot ID if provided
$project = "Oxide." + $game_name
if ($steam_depot) { $steam_depot = "-depot $steam_depot" }
# Set directory/file variables and create directories
$root_dir = $PSScriptRoot
$tools_dir = Join-Path $root_dir "tools"
$project_dir = Join-Path $root_dir "src"
$resources_dir = Join-Path $root_dir "resources"
$deps_dir = Join-Path $project_dir "Dependencies"
$platform_dir = Join-Path $deps_dir $platform
$managed_dir = Join-Path $platform_dir $managed_dir # TODO: Make sure passed path is Linux-compatible
$docs_dir = Join-Path $root_dir "docs"
$patcher_exe = Join-Path $tools_dir "OxidePatcher.exe"
$references_file = Join-Path $tools_dir ".references"
New-Item "$tools_dir", "$managed_dir", "$docs_dir" -ItemType Directory -Force | Out-Null
# Set URLs of dependencies and tools to download
$steam_depotdl_url = "https://img.mrblue.io/bf641959245341c381cffc95f38a2bc6.zip"
$de4dot_url = "https://github.com/0xd4d/de4dot/suites/507020524/artifacts/2658127"
$patcher_url = "https://github.com/OxideMod/Oxide.Patcher/releases/download/latest/OxidePatcher.exe"
# Set file path for patcher file (.opj)
$patcher_file = Join-Path $resources_dir "$game_name.opj"
# Set project file and get contents
$csproj = Get-Item "$project.csproj"
$xml = [xml](Get-Content $csproj)
# Remove patched file(s) and replace with _Original file(s)
Get-ChildItem (Join-Path $managed_dir "*_Original.*") -Recurse | ForEach-Object {
Remove-Item $_.FullName.Replace("_Original", "")
Rename-Item $_ $_.Name.Replace("_Original", "")
}
# TODO: Add support for GitHub API tokens for higher rate limit
function Find-Dependencies {
# Check if project file exists for game
if (!(Test-Path "$project.csproj")) {
Write-Host "Error: Could not find a .csproj file for $game_name"
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
exit 1
}
# Copy any local dependencies
$deps_pattern = Join-Path $deps_dir "Original" "*.dll"
if (Test-Path $deps_pattern) {
Copy-Item $deps_pattern $managed_dir -Force
}
# Check if Steam is used for game dependencies
if ($steam_access.ToLower() -ne "nosteam") {
# Get references from .csproj file
Write-Host "Getting references for $steam_branch branch of $steam_appid"
try {
# TODO: Exclude dependencies included in repository
if ($references_override) {
$references_override | Out-File $references_file
Write-Host "References:" ((Get-Content $references_file) -Join ', ')
} else {
($xml.selectNodes("//Reference") | Select-Object Include -ExpandProperty Include) -Replace "\S+$", "regex:$&.dll" | Out-File $references_file
Write-Host "References:" ((Get-Content $references_file).Replace('regex:', '') -Join ', ')
}
} catch {
Write-Host "Error: Could not get references or none found in $project.csproj"
Write-Host $_.Exception | Format-List -Force
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
exit 1
}
Get-Downloader
} else {
Get-Dependencies
}
}
function Get-Downloader {
# Check if DepotDownloader is already downloaded
$steam_depotdl_dll = Join-Path $tools_dir "DepotDownloader.exe"
$steam_depotdl_zip = Join-Path $tools_dir "DepotDownloader.zip"
if (!(Test-Path $steam_depotdl_dll) -or (Get-Item $steam_depotdl_dll).LastWriteTime -lt (Get-Date).AddDays(-7)) {
# Download and extract DepotDownloader
Write-Host "Downloading latest version of DepotDownloader"
try {
Invoke-WebRequest $steam_depotdl_url -OutFile $steam_depotdl_zip -UseBasicParsing
} catch {
Write-Host "Error: Could not download DepotDownloader"
Write-Host $_.Exception | Format-List -Force
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
exit 1
}
# TODO: Compare size and hash of .zip vs. what GitHub has via API
Write-Host "Extracting DepotDownloader release files"
Expand-Archive $steam_depotdl_zip -DestinationPath $tools_dir -Force
if (!(Test-Path $steam_depotdl_zip)) {
Get-Downloader # TODO: Add infinite loop prevention
return
}
# Cleanup downloaded .zip file
Remove-Item $steam_depotdl_zip
} else {
Write-Host "Recent version of DepotDownloader already downloaded"
}
Get-Dependencies
}
function Get-Dependencies {
if ($steam_access.ToLower() -ne "nosteam") {
# TODO: Add handling for SteamGuard code entry
# Check if Steam login information is required or not
$steam_file = Join-Path $root_dir ".steamlogin"
if ($steam_access.ToLower() -ne "anonymous") {
if (Test-Path $steam_file) {
$steam_login = Get-Content $steam_file
if ($steam_login.Length -ne 2) {
Write-Host "Steam username and password not set in .steamlogin file"
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
exit 1
} else {
$steam_access = "-username $($steam_login[0]) -password $($steam_login[1])"
}
} elseif ($env:STEAM_USERNAME -and $env:STEAM_PASSWORD) {
$steam_access = "-username $env:STEAM_USERNAME -password $env:STEAM_PASSWORD"
} else {
Write-Host "Error: No Steam credentials found, skipping build for $game_name"
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
exit 1
}
}
# Cleanup existing game files, else they are not always the latest
#Remove-Item $managed_dir -Recurse -Force
# TODO: Check for and compare Steam buildid before downloading again
# Attempt to run DepotDownloader to get game DLLs
try {
Write-Host "$steam_access -app $steam_appid -branch $steam_branch $steam_depot -os $platform -dir $deps_dir"
Start-Process $steam_depotdl_dll -WorkingDirectory $tools_dir -ArgumentList "$steam_access -app $steam_appid -branch $steam_branch $steam_depot -os $platform -dir $platform_dir -filelist $references_file" -NoNewWindow -Wait
} catch {
Write-Host "Error: Could not start or complete getting dependencies"
Write-Host $_.Exception | Format-List -Force
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
exit 1
}
# TODO: Store Steam buildid somewhere for comparison during next check
# TODO: Confirm all dependencies were downloaded (no 0kb files), else stop or retry and error with details
}
# Get package references from .csproj file
Write-Host "Getting package references for $game_name"
$packages = $null
try {
$packages = $xml.selectNodes("//PackageReference") | Select-Object Include,Version
Write-Host "Packages:" (($packages | Select-Object -ExpandProperty Include) -Join ', ')
} catch {
Write-Host "Error: Could not get package references or none found in $project.csproj"
Write-Host $_.Exception | Format-List -Force
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
exit 1
}
# Copy latest package references for patching
Write-Host "Copying latest package references for $game_name"
try {
# Copy package references specified in .csproj file
ForEach ($package in $packages) {
Write-Host "Copying package reference $($package.Include) $($package.Version)..."
$lib = Join-Path $root_dir "packages" $package.Include.ToLower() $package.Version.ToLower() "lib" $dotnet "$($package.Include).dll"
Copy-Item $lib $managed_dir -Force
Copy-Item $lib $tools_dir -Force
}
} catch {
Write-Host "Error: Could not copy one or more dependencies to $deps_dir or $tools_dir"
Write-Host $_.Exception | Format-List -Force
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
exit 1
}
if ($deobfuscator) {
Get-Deobfuscators
} else {
Get-Patcher
}
}
function Get-Deobfuscators {
# Check for which deobfuscator to get and use
if ($deobfuscator.ToLower() -eq "de4dot") {
$de4dot_dir = Join-Path $tools_dir ".de4dot"
$de4dot_dll = Join-Path $de4dot_dir "de4dot.dll"
$de4dot_zip = Join-Path $de4dot_dir "de4dot.zip"
New-Item $de4dot_dir -ItemType Directory -Force | Out-Null
# Check if de4dot is already downloaded
if (!(Test-Path $de4dot_dll) -or (Get-Item $de4dot_dll).LastWriteTime -lt (Get-Date).AddDays(-7)) {
# Download and extract de4dot
Write-Host "Downloading latest version of de4dot" # TODO: Get and show version
try {
Invoke-WebRequest $de4dot_url -OutFile $de4dot_zip -UseBasicParsing
#Invoke-WebRequest "https://github.com/0xd4d/de4dot/suites/266206734/artifacts/128547" -Out "$de4dot_dir\de4dot.zip"
} catch {
Write-Host "Error: Could not download de4dot"
Write-Host $_.Exception | Format-List -Force
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
exit 1
}
# TODO: Compare size and hash of .zip vs. what GitHub has via API
Write-Host "Extracting de4dot release files"
Expand-Archive "$de4dot_dir\de4dot.zip" -DestinationPath "$de4dot_dir" -Force
Move-Item "$de4dot_dir\de4dot-net35\*" $de4dot_dir
Remove-Item "$de4dot_dir\de4dot-net35"
if (!(Test-Path $de4dot_dll)) {
Get-Deobfuscators # TODO: Add infinite loop prevention
return
}
# Cleanup downloaded .zip file
Remove-Item $de4dot_zip
} else {
Write-Host "Recent version of de4dot already downloaded"
}
Start-Deobfuscator
}
}
function Start-Deobfuscator {
if ($deobfuscator.ToLower() -eq "de4dot") {
# Attempt to deobfuscate game file(s)
try {
Start-Process dotnet -WorkingDirectory $managed_dir -ArgumentList "$de4dot_dll -r $managed_dir -ru" -NoNewWindow -Wait
} catch {
Write-Host "Error: Could not start or complete deobufcation process"
Write-Host $_.Exception | Format-List -Force
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
exit 1;
}
# Remove obfuscated file(s) and replace with cleaned file(s)
Get-ChildItem (Join-Path $managed_dir "*-cleaned.*") -Recurse | ForEach-Object {
Remove-Item $_.FullName.Replace("-cleaned", "")
Rename-Item $_ $_.Name.Replace("-cleaned", "")
Write-Host "Deobfuscated and cleaned $_ file to patch"
}
}
Get-Patcher
}
function Get-Patcher {
# TODO: MD5 comparison of local patcher file and remote header
# Check if patcher is already downloaded
if (!(Test-Path $patcher_exe) -or (Get-Item $patcher_exe).LastWriteTime -lt (Get-Date).AddDays(-7)) {
# Download latest patcher build
Write-Host "Downloading latest version of Oxide patcher"
try {
Invoke-WebRequest $patcher_url -OutFile $patcher_exe -UseBasicParsing
} catch {
Write-Host "Error: Could not download Oxide patcher"
Write-Host $_.Exception | Format-List -Force
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
exit 1
}
} else {
Write-Host "Recent build of patcher already downloaded"
}
Start-Patcher
}
function Start-Patcher {
# Check if we need to get the patcher
if (!(Test-Path $patcher_exe)) {
Get-Patcher # TODO: Add infinite loop prevention
return
}
# TODO: Make sure dependencies exist before trying to patch
# Attempt to patch game using the patcher
try {
if ($IsLinux) {
Start-Process mono -WorkingDirectory $managed_dir -ArgumentList "$patcher_exe -c -p `"$managed_dir`" $patcher_file" -NoNewWindow -Wait
} elseif ($IsWindows) {
Start-Process $patcher_exe -WorkingDirectory $managed_dir -ArgumentList "-c -p `"$managed_dir`" -docs $docs_dir/docs.json $patcher_file" -NoNewWindow -Wait
}
} catch {
Write-Host "Error: Could not start or complete patching process"
Write-Host $_.Exception | Format-List -Force
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
exit 1
}
}
Find-Dependencies