-
Notifications
You must be signed in to change notification settings - Fork 41
Expand file tree
/
Copy pathcommon.sh
More file actions
268 lines (215 loc) · 7.47 KB
/
common.sh
File metadata and controls
268 lines (215 loc) · 7.47 KB
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
#!/bin/bash
# Use C locale for consistent sorting and string operations
export LC_ALL=C
# Resolve the directory where this script lives
ROOT_DIR="$(dirname "$(realpath -s "${BASH_SOURCE[0]}")")"
# Append .exe suffix on Windows
EXE_SUFFIX=""
if [[ "$(uname -s)" == MINGW* ]] || [[ "$(uname -s)" == MSYS* ]]; then
EXE_SUFFIX=".exe"
fi
# Tool paths
VRF_PATH="$ROOT_DIR/tools/exe/Source2Viewer/Source2Viewer-CLI${EXE_SUFFIX}"
PROTOBUF_DUMPER_PATH="$ROOT_DIR/tools/exe/ProtobufDumper/ProtobufDumper${EXE_SUFFIX}"
DUMP_STRINGS_PATH="$ROOT_DIR/tools/exe/DumpStrings${EXE_SUFFIX}"
STEAM_FILE_DOWNLOADER_PATH="$ROOT_DIR/tools/exe/SteamFileDownloader/SteamFileDownloader${EXE_SUFFIX}"
FIX_ENCODING_PATH="$ROOT_DIR/tools/exe/FixEncoding${EXE_SUFFIX}"
# Allow disabling git operations by passing "no-git" as the first or second argument
DO_GIT=1
if [[ $# -gt 0 ]]; then
if [[ $1 = "no-git" ]] || [[ $# -gt 1 && $2 = "no-git" ]]; then
DO_GIT=0
fi
fi
# _StringsPath - Derives the _strings.txt path from a binary file path and its extension.
# .exe files append _strings.txt (foo.exe -> foo.exe_strings.txt),
# other extensions replace the suffix (foo.dll -> foo_strings.txt).
# @param $1 - File path
# @param $2 - File extension
_StringsPath ()
{
if [[ "$2" == ".exe" ]]; then
echo "${1}_strings.txt"
else
echo "${1/%$2/_strings.txt}"
fi
}
# _ProcessBinary - Processes a single binary file by dumping protobufs and extracting strings.
# @param $1 - File path to process
# @param $2 - File extension (e.g. .dll, .so, .dylib, .exe)
_ProcessBinary ()
{
local file="$1"
local ext="$2"
# Skip common not game-specific binaries
local name
name="$(basename "$file" "$ext")"
if [[ "$name" = "steamclient" ]] || [[ "$name" = "libcef" ]]; then
return
fi
echo " $file"
# Extract protobuf definitions from the binary
"$PROTOBUF_DUMPER_PATH" "$file" "Protobufs/" > /dev/null
# Extract readable strings from the binary, sort and deduplicate them
"$DUMP_STRINGS_PATH" -binary "$file" | sort --unique > "$(_StringsPath "$file" "$ext")"
}
# ProcessDepot - Processes binary files by dumping protobufs and extracting strings.
# @param $@ - File extensions to process (e.g. .dll .so .dylib .exe)
ProcessDepot ()
{
echo "::group::Processing binaries ($*)"
# rm -r "Protobufs"
mkdir -p "Protobufs"
local max_jobs=10
local job_count=0
for ext in "$@"; do
# Find all files matching the given extension and process each one
while IFS= read -r -d '' file
do
_ProcessBinary "$file" "$ext" &
((++job_count))
if ((job_count >= max_jobs)); then
wait -n
((job_count--))
fi
done < <(find . -type f -name "*$ext" -print0)
done
wait
echo "::endgroup::"
}
# ProcessVPK - Lists contents of VPK directory files and writes them to corresponding .txt files.
ProcessVPK ()
{
echo "::group::Processing VPKs"
# Find all VPK directory files and dump their file listings to .txt
while IFS= read -r -d '' file
do
echo " $file"
# Write the VPK's file list to a .txt file with the same name
"$VRF_PATH" --input "$file" --vpk_list > "${file/%.vpk/.txt}"
done < <(find . -type f -name "*_dir.vpk" -print0)
echo "::endgroup::"
}
# _DeduplicateStringsFile - Deduplicates a single strings file against a merged reference.
# @param $1 - Strings file to deduplicate
# @param $2 - Merged dedupe reference file
_DeduplicateStringsFile ()
{
local target_file="$1"
local merged_dedupe="$2"
# Remove lines present in reference files and replace the original
comm -23 "$target_file" "$merged_dedupe" > "$target_file.tmp"
mv "$target_file.tmp" "$target_file"
}
# DeduplicateStringsFrom - Removes duplicate string lines from extracted strings files
# by filtering out lines that appear in the provided dedupe reference files.
# @param -- - Separator between suffixes and reference files
# @usage DeduplicateStringsFrom .dll .exe -- file1.txt file2.txt
DeduplicateStringsFrom ()
{
# Split arguments into suffixes (before --) and reference files (after --)
local suffixes=()
local ref_files=()
local found_separator=0
for arg in "$@"; do
if [[ "$arg" == "--" ]]; then
found_separator=1
elif ((found_separator)); then
ref_files+=("$arg")
else
suffixes+=("$arg")
fi
done
echo "::group::Deduplicating strings (${suffixes[*]})"
# Resolve all dedupe reference files to absolute paths, warn if missing
local dedupe_files=()
for file in "${ref_files[@]}"; do
local resolved
resolved="$(realpath "$file")"
if [[ -f "$resolved" ]]; then
dedupe_files+=("$resolved")
else
echo "::warning::Dedupe file not found: $file"
fi
done
# Merge all reference files into a single sorted set
local merged_dedupe
merged_dedupe="$(mktemp)"
sort --unique --merge "${dedupe_files[@]}" > "$merged_dedupe"
local max_jobs=10
local job_count=0
for suffix in "${suffixes[@]}"; do
# Iterate over all binaries matching the suffix and process their strings files
while IFS= read -r -d '' file
do
# Derive the corresponding _strings.txt path from the binary path
local target_file
target_file="$(_StringsPath "$(realpath "$file")" "$suffix")"
# Skip if no strings file exists for this binary
if ! [[ -f "$target_file" ]]; then
continue
fi
# Don't deduplicate a file against itself
for dedupe_file in "${dedupe_files[@]}"; do
if [[ "$dedupe_file" = "$target_file" ]]; then
continue 2
fi
done
_DeduplicateStringsFile "$target_file" "$merged_dedupe" &
((++job_count))
if ((job_count >= max_jobs)); then
wait -n
((job_count--))
fi
done < <(find . -type f -name "*$suffix" -print0)
done
wait
rm -f "$merged_dedupe"
echo "::endgroup::"
}
# ProcessToolAssetInfo - Converts binary tools asset info files (*asset_info.bin) to readable .txt format.
ProcessToolAssetInfo ()
{
echo "::group::Processing tools asset info"
# Find all tools asset info binaries and convert them to text
while IFS= read -r -d '' file
do
echo " $file"
# Dump asset info in short format, replacing .bin extension with .txt
"$VRF_PATH" --input "$file" --output "${file/%.bin/.txt}" --tools_asset_info_short || echo "S2V failed to dump tools asset info"
done < <(find . -type f -name "*asset_info.bin" -print0)
echo "::endgroup::"
}
# FixUCS2 - Converts UCS-2 encoded .txt files to UTF-8 using the FixEncoding tool.
FixUCS2 ()
{
echo "::group::Fixing encodings"
# Run FixEncoding on all .txt files in parallel (up to 3 at a time)
find . -type f -name "*.txt" -print0 | xargs --null --max-lines=1 --max-procs=3 "$FIX_ENCODING_PATH"
echo "::endgroup::"
}
# CreateCommit - Stages all changes, creates a git commit with a summary message, and pushes.
# @param $1 - Commit message prefix (e.g. game/app name)
# @param $2 - (optional) Patch notes ID appended as a SteamDB URL in the commit body
CreateCommit ()
{
# Skip if git operations were disabled via "no-git" argument
if ! [[ $DO_GIT == 1 ]]; then
echo "Not performing git commit"
return
fi
echo "::group::Creating commit"
# Stage all changes including untracked files
git add --all
# Build commit message: "<prefix> | <file count> files | <comma-separated change list truncated to 1024 chars>"
message="$1 | $(git diff --cached --numstat | wc -l) files | $(git diff --cached --name-status | sed '{:q;N;s/\n/, /g;t q}' | cut -c 1-1024)"
# Append a SteamDB patchnotes link if a patch notes ID was provided
if [[ -n "$2" ]]; then
bashpls=$'\n\n'
message="${message}${bashpls}https://steamdb.info/patchnotes/$2/"
fi
# Commit (allow failure if there are no changes) and push
git commit --message "$message" || true
git push
echo "::endgroup::"
}