· 4 years ago · Aug 02, 2021, 02:10 PM
1#!/bin/bash
2
3SHOW_BRIEF() {
4cat << EOH
5
6Usage:
7 ./warframe_install.sh download [release]
8 ./warframe_install.sh [--no-update|--force-update] [--overwrite] extract [proton_tar]
9 ./warframe_install.sh [--no-update|--force-update] [--overwrite] proton [release|proton_tar]
10 ./warframe_install.sh [-y] vulkan
11 ./warframe_install.sh after
12 ./warframe_install.sh [--no-update|--force-update] [--overwrite] [-y] all [release|proton_tar]
13 ./warframe_install.sh help
14
15EOH
16}
17
18SHOW_HELP() {
19cat << EOH
20Prepare to run Warframe (and perhaps other Windows games) on Linux
21using GloriousEggroll's custom version of Proton.
22
23This script last updated 2020-07-31.
24
25Usage:
26 ./warframe_install.sh download [release]
27 Download GloriousEggroll's custom version of Proton from:
28 https://github.com/GloriousEggroll/proton-ge-custom/releases
29 If release is specified, download that specific release.
30 Use "latest" to specify the latest stable release.
31 Use a tag name (eg "5.2-GE-1") to specify a specific release.
32 If ommited, downloads release index 0 in the list of releases,
33 which should be the latest release, including unstable versions.
34 Accepts a github api URL as well;
35 Must return either a single release or a list of releases.
36 If started from your home directory, places archive under ~/Downloads.
37 Otherwise, output is placed is current working directory.
38
39 ./warframe_install.sh [--no-update|--force-update] [--overwrite] extract [proton_tar]
40 Install GloriousEggroll's custom version of Proton.
41 Must be downloaded first from:
42 https://github.com/GloriousEggroll/proton-ge-custom/releases
43 It is recommended to use the latest release,
44 even if it is labelled testing.
45 proton_tar may contain the path of the downloaded tar.
46 Otherwise, the current directory and ~/Downloads are checked.
47 Will not extract if extraction dir already exists, unless --overwrite is used.
48 By default, creates and updates a special "Proton-GE-latest" entry
49 for ease in updating. --no-update disables this.
50 --force-update will update even if extraction dir already exists.
51 Set your games to use "Proton-GE-latest", and you won't have to change
52 the settings of every game each time you update proton any more.
53 Of course, you can always still chose a specific version for some games.
54
55 ./warframe_install.sh [--no-update|--force-update] [--overwrite] proton [release|proton_tar]
56 Do both previous actions (download and extract).
57 If 2nd parameter contains :// (colon slash slash), it is interpreted
58 as a github api url, which will return release information in JSON.
59 If 2nd parameter contains / (single forward slash), it is interpreted
60 as a local path to the tar of Proton, and nothing is downloaded.
61 Otherwise, it is interpteted as the release name to download.
62 Therefore, use ./file to indicate a file in the current directory.
63
64 ./warframe_install.sh [-y] vulkan
65 ./warframe_install.sh [-y] driver
66 ./warframe_install.sh [-y] drivers
67 Install Vulkan driers. (Both 64 and 32-bit, if applicable.)
68 If -y is specified, install proceeds without prompting.
69
70 ./warframe_install.sh after
71 Print instructions on what you must do manually after
72 running this script.
73
74 ./warframe_install.sh [--no-update|--force-update] [-y] [--overwrite] all [release|proton_tar]
75 ./warframe_install.sh [--no-update|--force-update] [-y] [--overwrite] "*" [release|proton_tar]
76 Do all three previous actions.
77 proton -> vulkan -> after
78
79 ./warframe_install.sh help
80 ./warframe_install.sh --help
81 Print this help.
82
83 There is LIMITED support for performing multiple actions at once.
84 If more than one action is specified, be aware that any optional
85 parameters after the action name become mandatory to all options
86 before the last.
87 For example,
88 ./warframe_install.sh vulkan extract
89 or
90 ./warframe_install.sh extract "" vulkan
91 will do what you intend (albeit in different orders), while
92 ./warframe_install.sh extract vulkan
93 will attempt to extract a tar file named "vulkan".
94 Also, make sure you specify a flag such as --force-update or -y
95 BEFORE the relevant action, or it will have no effect.
96EOH
97}
98SHOW_AFTER() {
99BEGIN after
100cat << 'EOA'
101
102OK. The automatic bit is done. Here's what you need to do manually:
103
1041) Make sure the graphics drivers for your video card are installed.
105 If Warframe complains about DirectX 9 being End of Life,
106 it means that the graphics drivers are not installed properly.
107 You need the latest proprietary drivers for your card, available
108 from the Ubuntu Driver Manager.
109
1102) Launch Steam.
111 If Steam was already open, exit completely and relaunch it.
112 If you do not properly restart Steam, you WILL NOT see your
113 new version of Proton! You must specifically tell Steam to exit,
114 not just close all of its windows.
115
116You have two options:
117 A) Set the individual game (in this example Warframe)
118 to use the version of Proton just installed.
119 B) Set ALL applicable games to default to using the version
120 of Proton just installed. Note that games can be
121 overriden to use a different version using option A.
122
123OPTION A: (Set games individually)
124
1253A) Go to the Warframe page in your library.
126
1274A) Open Warframe's properties.
128 Either
129 In the side pannel list of games
130 Right click on Warframe
131 Choose "Properties..."
132 OR
133 Click the gear button towards the right ("Manage")
134 Choose "Properties..."
135
1365A) In the "Warframe - Properties" popup, on the GENERAL tab,
137 check the box at the bottom labelled
138 "Force the use of a specific Steam Play compatability tool"
139
1406A) Select the custom version of Proton you just installed,
141 which should be near the top of the list and contain "-GE-".
142 Alternatively, select "Proton-GE-latest" to always use the
143 most recent version of Proton installed with this tool.
144
1457A) Click CLOSE.
146
1478A) Click INSTALL.
148
149OPTION B: (set all Windows games to use Proton)
150
1513B) Open the Steam Settings.
152 Either
153 In the upper left of the main window,
154 select Steam and then Settings from that menu.
155 OR
156 Right click the system tray icon.
157 Select Settigns.
158
1594B) From the headings on the left of the Settings window,
160 select "Steam Play" (near the bottom).
161
1625B) Check "Enable Steam Play for all other titles".
163
1646B) In the "Run other titles with:" drop down,
165 select the version of Proton just installed,
166 which should be near the top of the list and contain "-GE-".
167 Alternatively, select "Proton-GE-latest" to always use the
168 most recent version of Proton installed with this tool.
169 Click "OK".
170
1717B) Steam will inform you that it must restart for the change to
172 take effect. Click "Restart Steam" to do so.
173 ( After Steam has restarted, if you go back to this option,
174 you may see it unchecked, as if you had never enabled it.
175 THIS IS A KNOWN BUG IN STEAM. The option has taken effect,
176 but Steam won't show it enabled on this screen. If you
177 actually try installing a game, it should work even though
178 it appears unchecked here. )
179
180There. That wasn't so bad, was it? ^_^
181
182NOW DON'T FORGET! Once Warframe finishes installing,
183you need to tweak some settings in game for better performance:
184
185- Warframe is problematic with vsync.
186 Turn it off or on in game, do not set Auto.
187- Warframe needs a set a frame limit in game.
188 Unlimited framerate can cause slowdowns.
189- Warframe on Nvidia you may need to disable GPU Particles
190 in game otherwise the game can freeze randomly.
191 On AMD they work fine.
192
193Based on instructions from helpful users and those found on
194https://github.com/GloriousEggroll/proton-ge-custom
195This installer is MIT liscenced and was written by
196@NerdyWhiteGuy#5108 on https://discord.gg/6y3BdzC
197
198 _______________________________________________
199 / \
200 | Hey there! A lot of information has just been |
201 | printed to your terminal. Make sure to scroll |
202 | up and read it. In particular, read the part |
203 | starting with "OK. The automatic bit is done." |
204 | and ending here. Have a nice day! :-) |
205 \ _____________________________________________/
206 \/
207 \ O
208 -+-
209 |
210 / \
211EOA
212END
213}
214
215BEGIN() {
216 CURRENT_ACTION="$1"
217 echo -e " - \e[1mBeginning action: $1\e[0m"
218}
219END() {
220 # Use the value of $1 if it is not the empty string.
221 # Otherwise, use $CURRENT_ACTION.
222 echo
223 echo -e " - \e[1mFinished action: ${1:-$CURRENT_ACTION}\e[0m"
224}
225
226DETECT_DISTRO() {
227 # Don't re-test if distro has already been found.
228 [ -n "$DISTRO" ] && return
229 if type apt-get >& /dev/null >&1 ; then
230 DISTRO=debian
231 else
232 echo "Unable to determine distro." 1>&2
233 return 1
234 fi
235 echo "Distro detected as $DISTRO."
236 echo
237}
238
239DOWNLOAD_PROTON() {
240 # JSON parsing ideas: https://stackoverflow.com/a/1955555
241 BEGIN "download"
242 exec 3>&1
243 export GIT_RELEASE_ID="$1"
244 # Use the contents of $1 or the string "latest" to pick which version to fetch.
245 read SIZE DOWNLOAD < <( python3 -c 'import os, sys, requests
246fd3 = open(3,"w")
247URL_PREFIX = "https://api.github.com/repos/GloriousEggroll/proton-ge-custom/releases"
248release_id = os.environ["GIT_RELEASE_ID"]
249if release_id == "":
250 url = URL_PREFIX
251else:
252 if release_id == "latest":
253 url = URL_PREFIX + "/latest"
254 else:
255 try: # If release_id was a full URL, just use that.
256 release_id.index("://")
257 url = release_id
258 except ValueError: # Otherwise, treat it as a tag name.
259 url = URL_PREFIX + "/tags/" + release_id
260result = requests.get(url, headers={"Accept":"application/json"})
261release = result.json()
262if result.status_code >= 300:
263 print(release, file=fd3)
264 exit(1)
265if isinstance(release, list): # If we got a list, operate on first item.
266 release = release[0]
267assets = release["assets"]
268largest = len(assets)-1
269size = assets[largest]["size"]
270for i in range(1,len(assets)):
271 if assets[i]["size"] > size:
272 largest = i
273 size = assets[i]["size"]
274print("In release", release["tag_name"]+",", "file index", largest, "has a size of", size, "and is downloadable via", file=sys.stderr)
275print(assets[largest]["browser_download_url"], file=sys.stderr)
276print(file=fd3)
277print("# BEGIN RELEASE NOTES #", file=fd3)
278print(file=fd3)
279print(release["body"], file=fd3)
280print(file=fd3)
281print("# END RELEASE NOTES #", file=fd3)
282print(size, assets[largest]["browser_download_url"])' )
283 if [ $? = 0 ] && [ -n "$DOWNLOAD" ]; then
284 if [ "$HOME" = "$PWD" ] && [ -d ~/Downloads ]; then
285 INPUT=~/"Downloads/${DOWNLOAD##*/}"
286 else
287 INPUT="./${DOWNLOAD##*/}"
288 fi
289 echo
290 if [ -s "$INPUT" ]; then
291 echo "File $INPUT already exists."
292 REAL_SIZE=`wc -c "$INPUT" | cut -d ' ' -f 1`
293 if [ "$REAL_SIZE" = "$SIZE" ]; then
294 echo "File has correct size of $REAL_SIZE bytes."
295 echo "Delete or rename this file to download again."
296 END
297 return 0
298 else
299 echo "Existing file has INCORRECT size of $REAL_SIZE bytes."
300 echo "Existing file SHOULD have a size of $SIZE bytes."
301 echo "REMOVING existing file and RETRYING download."
302 rm "$INPUT"
303 if [ -z "$OVERWRITE" ]; then
304 echo "In case of in-place update or a corrupted extraction,"
305 echo "we will OVERWRITE any previous output."
306 OVERWRITE=auto
307 fi
308 fi
309 fi
310 if curl -L -o "$INPUT" "$DOWNLOAD"; then
311 echo "Saved file as $INPUT"
312 REAL_SIZE=`wc -c "$INPUT" | cut -d ' ' -f 1`
313 if [ "$REAL_SIZE" = "$SIZE" ]; then
314 END
315 return 0
316 else
317 echo "Downloaded file has wrong size!" 1>&2
318 echo "File should have size $SIZE," 1>&2
319 echo "but actually has size $REAL_SIZE." 1>&2
320 echo "NOT continuing. Run again to retry download." 1>&2
321 END
322 return 1
323 fi
324 else
325 echo "Download failed. Error code: $?" 1>&2
326 END
327 return 1
328 fi
329 else
330 echo "Failed to find URL of release tarball." 1>&2
331 END
332 return 2
333 fi
334}
335
336FIND_OUTPUT() {
337 OUTPUT="$1"
338 if ! [ -d "$1" ]; then
339 echo "$OUTPUT: No such file or directory" 1>&2
340 return 1
341 fi
342}
343
344FIND_INPUT() {
345 INPUT="`find "$1" -maxdepth 1 -iname 'Proton*-GE-*.tar*' -print0 | sort -z | tail -z --lines 1 | head --bytes -1`"
346 [ -n "$INPUT" ]
347}
348
349SETUP_LATEST() {
350 # Create a "latest" entry.
351 LATEST_VDF="$OUTPUT/Proton-GE-latest/compatibilitytool.vdf"
352 if ! [ -d "${LATEST_VDF%/*}" ] && [ -a "${LATEST_VDF%/*}" ] ; then
353 echo "${LATEST_VDF%/*} exists, but is not a directory." 1>&2
354 echo "NOT creating Proton-GE-latest entry." 1>&2
355 else
356 mkdir -p "${LATEST_VDF%/*}"
357 echo "Setting Proton-GE-latest to point to $EXTRACTED"
358 cat > "$LATEST_VDF" << EOVDF
359"compatibilitytools"
360{
361 "compat_tools"
362 {
363 "Proton-GE-latest" // Internal name of this tool
364 {
365 // Can register this tool with Steam in two ways:
366 //
367 // - The tool can be placed as a subdirectory in compatibilitytools.d, in which case this
368 // should be '.'
369 //
370 // - This manifest can be placed directly in compatibilitytools.d, in which case this should
371 // be the relative or absolute path to the tool's dist directory.
372 "install_path" "../$EXTRACTED"
373
374 // For this template, we're going to substitute the display_name key in here, e.g.:
375 "display_name" "Proton-GE-latest (Currently $EXTRACTED)"
376
377 "from_oslist" "windows"
378 "to_oslist" "linux"
379 }
380 }
381}
382EOVDF
383 fi
384}
385
386CAREFUL_DELETE() {
387 if [ -z "$1" ]; then
388 echo "FATAL ERROR: ATTEMPTED TO DELETE THE EMPTY STRING!" 2>&1
389 exit 3
390 fi
391 if pushd "$1" > /dev/null; then
392 RMDIR="$PWD"
393 popd > /dev/null
394 if [ "$RMDIR" = "$PWD" ]; then
395 echo "FATAL ERROR: ATTEMPTED TO DELETE THE CURRENT DIRECTORY!" 2>&1
396 exit 3
397 fi
398 if [ "$RMDIR" = "$HOME" ] || [[ "$RMDIR" =~ ^/home/[^/]+$ ]]; then
399 echo "FATAL ERROR: ATTEMPTED TO DELETE A HOME DIRECTORY!" 2>&1
400 exit 3
401 fi
402 if ! [[ "$RMDIR" =~ ^/home/[^/]+/ ]]; then
403 echo "FATAL ERROR: ATTEMPTED TO DELETE OUTSIDE OF YOUR HOME DIRECTORY!" 2>&1
404 exit 3
405 fi
406 if [ -L "$1" ]; then
407 echo "Removing symlink…"
408 rm -v "$1"
409 else
410 echo "Removing directory: $RMDIR"
411 rm --one-file-system -rI "$RMDIR"
412 fi
413 else
414 echo "Could not enter $1" 2>&1
415 echo "NOT attempting to delete." 2>&1
416 return 1
417 fi
418}
419
420EXTRACT_PROTON() {
421 # Based on instructions from https://github.com/GloriousEggroll/proton-ge-custom
422 BEGIN "extract"
423 echo "Extract the downloaded tar of Proton into Steam's compatability tools folder."
424 echo
425 if ! FIND_OUTPUT ~/.steam/root; then
426 if ! FIND_OUTPUT ~/.var/app/com.valvesoftware.Steam/data/Steam; then
427 echo "Unable to find Steam install in the usual places."
428 echo "Make sure you've installed it and run it at least once."
429 exit 1
430 fi
431 fi 1>&2
432 if [ -z "$INPUT" ]; then
433 if [ -z "$1" ]; then
434 if ! FIND_INPUT .; then
435 if ! FIND_INPUT ~/Downloads; then
436 echo "Proton*-GE-*.tar*: No such file or directory"
437 echo "Unable to find Proton installer."
438 echo "Please download the latest release (testing are OK) from"
439 echo "https://github.com/GloriousEggroll/proton-ge-custom/releases"
440 echo "and place it in either the current directory or ~/Downloads"
441 exit 1
442 fi
443 fi 1>&2
444 else
445 INPUT="$1"
446 fi
447 else
448 echo "Using preestablished input file: $INPUT" 1>&2
449 fi
450 OUTPUT="$OUTPUT/compatibilitytools.d"
451 mkdir -p "$OUTPUT"
452 echo "Preparing to extract Proton into the following directory:"
453 echo "$OUTPUT"
454 # Get dir name from inside archive.
455 EXTRACTED="`tar -tf "$INPUT" | head -n 1`"
456 # Trim trailing /
457 EXTRACTED="${EXTRACTED%%/*}"
458 if [ -z "$EXTRACTED" ]; then
459 echo "Reading from tar '$INPUT' FAILED!" 1>&2
460 END
461 return $code
462 fi
463 if [ -a "$OUTPUT/$EXTRACTED" ]; then
464 if [ "$OVERWRITE" = "auto" ] || [ "$OVERWRITE" = "yes" ]; then
465 echo "$OUTPUT/$EXTRACTED already exists. DELETING." 1>&2
466 if ! CAREFUL_DELETE "$OUTPUT/$EXTRACTED" || [ -a "$OUTPUT/$EXTRACTED" ]; then
467 echo "NOT deleted. Aborting extract."
468 if [ "$UPDATE_LATEST" = "force" ]; then
469 echo
470 echo "Setting up of \"Proton-GE-latest\" entry forced. (via --update-force)"
471 SETUP_LATEST
472 fi
473 END
474 return 1
475 fi
476 else
477 echo "$OUTPUT/$EXTRACTED already exists. NOT extracting over it." 1>&2
478 echo "Delete or rename the existing copy to extract to this directory." 1>&2
479 if [ "$UPDATE_LATEST" = "force" ]; then
480 echo
481 echo "Setting up of \"Proton-GE-latest\" entry forced. (via --update-force)"
482 SETUP_LATEST
483 fi
484 END
485 return 0
486 fi
487 fi
488 if # Test for success of entire extraction process.
489 if type pv >& /dev/null >&1 ; then # If pv is available, use it.
490 pv "$INPUT" | tar -x -C "$OUTPUT" -z
491 else
492 echo "(Consider installing the pv utility to see a progress bar here.)"
493 tar -x -C "$OUTPUT" -zf "$INPUT"
494 fi
495 then
496 echo
497 if [ "$UPDATE_LATEST" != "no" ]; then
498 SETUP_LATEST
499 else
500 echo "NOT setting \"Proton-GE-latest\" entry. (Dissabled via --no-update)"
501 fi
502 END
503 return 0
504 else
505 code=$?
506 echo "Extracting tar FAILED! Code $code" 1>&2
507 END
508 return $code
509 fi
510}
511
512INSTALL_PROTON() {
513 BEGIN "proton"
514 if [ -z "$1" ] && [[ "$1" != *://* ]] && [[ "$1" == */* ]]; then
515 # Is not the empty string,
516 # does NOT contain colon slash slash,
517 # DOES contain a slash.
518 # Therefore, it is a path.
519 # Note that [[ ]] uses pattern matching while [ ] does not.
520 EXTRACT_PROTON "$1"
521 else
522 # Otherwise, it is not a path.
523 DOWNLOAD_PROTON "$1" && EXTRACT_PROTON
524 fi
525 code=$?
526 END "proton"
527 return $code
528}
529
530INSTALL_VULKAN() {
531 BEGIN "vulkan"
532 echo "Installing Vulkan graphics drivers."
533 echo "Required to actually launch the game."
534 echo
535 DETECT_DISTRO
536 case "$DISTRO" in
537 debian)
538 # Architechture detection: https://akrabat.com/installing-32-bit-packages-on-ubuntu-14-04/
539 ARC="`dpkg --print-architecture`"
540 # Detect and install Mesa Vulkan drivers for native architecture.
541 if dpkg-query -W --showformat='${Status}\n' mesa-vulkan-drivers:$ARC 2> /dev/null | grep -qF "install ok installed"; then
542 echo "mesa-vulkan-drivers:$ARC appears to be already installed."
543 else
544 echo "Installing mesa-vulkan-drivers:$ARC..."
545 sudo apt-get $AUTO_INSTALL install mesa-vulkan-drivers:$ARC
546 fi
547 # If architecture is amd64 (aka 64-bit), also check i386 (aka 32-bit).
548 if [ "$ARC" = "amd64" ]; then
549 echo
550 if dpkg-query -W --showformat='${Status}\n' mesa-vulkan-drivers:i386 2> /dev/null | grep -qF "install ok installed"; then
551 echo "mesa-vulkan-drivers:i386 appears to be already installed."
552 else
553 if ! dpkg --print-foreign-architectures | grep -q "i386" ; then
554 echo "Adding the i386 architechture..."
555 sudo dpkg --add-architecture i386
556 sudo apt-get update
557 echo
558 fi
559 echo "Installing mesa-vulkan-drivers:i386..."
560 sudo apt-get $AUTO_INSTALL install mesa-vulkan-drivers:i386
561 fi
562 fi
563 ;;
564 *)
565 echo "Can't install Vulkan drivers automatically." 1>&2
566 echo "It is up to you to ensure these drivers are installed." 1>&2
567 ;;
568 esac
569 END
570}
571
572PROCESS_ARG() {
573 CONSUME_ARGS=1
574 case $1 in
575 "")
576 SHOW_BRIEF
577 exit 2
578 ;;
579 help|--help)
580 SHOW_HELP
581 ;;
582 download)
583 DOWNLOAD_PROTON "$2"
584 CONSUME_ARGS=2
585 ;;
586 extract)
587 EXTRACT_PROTON "$2"
588 CONSUME_ARGS=2
589 ;;
590 proton)
591 INSTALL_PROTON "$2"
592 CONSUME_ARGS=2
593 ;;
594 vulkan)
595 INSTALL_VULKAN
596 ;;
597 after)
598 SHOW_AFTER
599 ;;
600 "*"|all)
601 INSTALL_PROTON "$2" && INSTALL_VULKAN && SHOW_AFTER
602 # Repeated && above is to abort if an error is encountered.
603 CONSUME_ARGS=2
604 ;;
605 --no-update)
606 UPDATE_LATEST=no
607 ;;
608 --force-update)
609 UPDATE_LATEST=force
610 ;;
611 --overwrite)
612 OVERWRITE=yes
613 ;;
614 -y)
615 # The value of this variable is conveniently the flag
616 # passed to many tools to disable prompting when
617 # installing new software. Of course, not all tools for
618 # all distros will use the same flag.
619 AUTO_INSTALL=-y
620 ;;
621 *)
622 echo "Unknown action: $1" 1>&2
623 SHOW_BRIEF
624 exit 2
625 ;;
626 esac
627}
628
629PROCESS_ARG "$1" "$2"
630# shift fails (and shifts nothing) if it tries to shift more args than exist.
631# Therefore, attempt to shift no more than the maximum number of args.
632shift "$(( CONSUME_ARGS > $# ? $# : CONSUME_ARGS ))"
633while (( $# >= 1 )); do
634 PROCESS_ARG "$1" "$2"
635 shift "$(( CONSUME_ARGS > $# ? $# : CONSUME_ARGS ))"
636done
637