Compare commits

..

No commits in common. "d91580f18ee40cda5ca7473b02753f8ccf8eceb4" and "e40c4e56d104b706a9c26bd1bc15f639422d07b7" have entirely different histories.

10 changed files with 131 additions and 339 deletions

@ -2,15 +2,6 @@ You can help us in the development of the project on the website: https://linux-
---------------------------------------- ----------------------------------------
Changelog: Changelog:
###Scripts version 2386### / Date: 09.01.2025 / Download update size: 4 megabytes
* corrected permissions when creating desktop files (thanks to Boria138)
* fixed the function of rolling back scripts from the archive if there is no scripts_backup directory (thanks to Boria138)
* added the ability to remove a game from the list in the Steam library using the functionality of changing the shortcut in PortProton (thanks to alex2844)
* when adding a game to the steam library, a check for the availability of the steamgriddb site has been added (thanks alex2844)
* added auto-installation of games (thanks to minergenon):
* Last Chaos
* Fractured Online
###Scripts version 2385### / stable / Date: 29.12.2024 / Download update size: 195 megabytes ###Scripts version 2385### / stable / Date: 29.12.2024 / Download update size: 195 megabytes
* cumulative update to the stable version of PortProton scripts * cumulative update to the stable version of PortProton scripts

@ -2,15 +2,6 @@
----------------------------------------- -----------------------------------------
История изменений: История изменений:
###Scripts version 2386### / Дата: 09.01.2025 / Размер скачиваемого обновления: 4 мегабайта
* исправление прав при создании desktop файлов (спасибо Boria138)
* исправлена функция отката скриптов из архива, если нет каталога scripts_backup (спасибо Boria138)
* добавлена возможность удаления игры из списка в библиотеке Steam с помощью функционала изменения ярлыка в PortProton (спасибо alex2844)
* при добавлении игры в библиотеку steam добавлена проверка на доступность сайта steamgriddb (спасибо alex2844)
* добавлены автоустановки игр (спасибо minergenon):
* Last Chaos
* Fractured Online
###Scripts version 2385### / stable / Дата: 29.12.2024 / Размер скачиваемого обновления: 195 мегабайт ###Scripts version 2385### / stable / Дата: 29.12.2024 / Размер скачиваемого обновления: 195 мегабайт
* кумулятивное обновление стабильной версии скриптов PortProton * кумулятивное обновление стабильной версии скриптов PortProton

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

@ -41,22 +41,19 @@ generateShortcutVDFHexAppId() {
} }
# Takes an signed 32bit integer and converts it to an unsigned 32bit integer # Takes an signed 32bit integer and converts it to an unsigned 32bit integer
extractSteamId32() { generateShortcutGridAppId() {
# STUID32=$((STUID64 - 76561197960265728))
echo $(($1 & 0xFFFFFFFF)) echo $(($1 & 0xFFFFFFFF))
} }
## ---------- ## ----------
### END MAGIC APPID FUNCTIONS ### END MAGIC APPID FUNCTIONS
getSteamShortcutsVdfFileHex() { getSteamShortcutsVdfFileHex() {
if [[ -z "${STCFGPATH}" ]]; then STCFGPATH="$(getUserPath)"
STCFGPATH="$(getUserPath)" if [[ -n "${STCFGPATH}" ]]; then
fi
if [[ -n "${STCFGPATH}" ]] && [[ -z "${SCPATH}" ]]; then
SCPATH="${STCFGPATH}/shortcuts.vdf" SCPATH="${STCFGPATH}/shortcuts.vdf"
fi if [[ -f "${SCPATH}" ]]; then
if [[ -n "${SCPATH}" ]] && [[ -f "${SCPATH}" ]]; then LC_ALL=C perl -0777 -ne 'print unpack("H*", $_)' "${SCPATH}"
LC_ALL=C perl -0777 -ne 'print unpack("H*", $_)' "${SCPATH}" fi
fi fi
} }
@ -74,14 +71,10 @@ getSteamShortcutEntryHex() {
printf "%s" "${SHORTCUTSVDFINPUTHEX}" | grep -oP "${SHORTCUTSVDFMATCHPATTERN}\K.*?(?=${SHORTCUTVDFENDPAT})" printf "%s" "${SHORTCUTSVDFINPUTHEX}" | grep -oP "${SHORTCUTSVDFMATCHPATTERN}\K.*?(?=${SHORTCUTVDFENDPAT})"
} }
getAppExe() {
[[ -n "$1" ]] && listNonSteamGames | jq -r --arg id "$1" 'map(select(.id == $id)) | first(.[].exe)'
}
getAppTarget() { getAppTarget() {
exe=$(getAppExe "$1") exe=$(listNonSteamGames | jq -r --arg id "$1" 'map(select(.id == $id)) | first(.[].exe)')
if [[ -n "${exe}" ]]; then if [[ -n "${exe}" ]]; then
if [[ "${exe}" =~ .sh$ ]]; then if [[ "${exe}" =~ .sh$ ]] ; then
parseSteamTargetExe "${exe}" parseSteamTargetExe "${exe}"
else else
echo "${exe}"; echo "${exe}";
@ -94,7 +87,7 @@ getSteamGameId() {
} }
getAppId() { getAppId() {
[[ -n "$1" ]] && listNonSteamGames | jq -r --arg exe "$1" 'map(select(.exe == $exe)) | first(.[]?.id)' listNonSteamGames | jq -r --arg exe "$1" 'map(select(.exe == $exe)) | first(.[]?.id)'
} }
getSteamId() { getSteamId() {
@ -107,16 +100,14 @@ getSteamId() {
if [[ -n "${SteamIds:-}" ]] && jq -e --arg key "$NOSTAPPNAME" 'has($key)' <<< "${SteamIds}" > /dev/null; then if [[ -n "${SteamIds:-}" ]] && jq -e --arg key "$NOSTAPPNAME" 'has($key)' <<< "${SteamIds}" > /dev/null; then
SteamAppId=$(jq -r --arg key "${NOSTAPPNAME}" '.[$key]' <<< "${SteamIds}") SteamAppId=$(jq -r --arg key "${NOSTAPPNAME}" '.[$key]' <<< "${SteamIds}")
else else
if [[ -n "${1:-}" ]] && [[ "${USE_STEABGRIDDB:-1}" == "1" ]]; then if [[ -n "${1:-}" ]]; then
getSteamGridDBId "${NOSTAPPNAME}" > /dev/null getSteamGridDBId "${NOSTAPPNAME}" > /dev/null
fi fi
if [[ $SteamGridDBTypeSteam == true ]]; then if [[ $SteamGridDBTypeSteam == true ]]; then
SRES=$(curl -Ls --connect-timeout 5 -m 10 -e "https://www.steamgriddb.com/game/${SteamGridDBId}" "https://www.steamgriddb.com/api/public/game/${SteamGridDBId}") SRES=$(curl -Ls -e "https://www.steamgriddb.com/game/${SteamGridDBId}" "https://www.steamgriddb.com/api/public/game/${SteamGridDBId}")
if jq -e ".success == true" <<< "${SRES}" > /dev/null 2>&1; then if jq -e ".success == true" <<< "${SRES}" > /dev/null 2>&1; then
SteamAppId="$(jq -r '.data.platforms.steam.id' <<< "${SRES}")" SteamAppId="$(jq -r '.data.platforms.steam.id' <<< "${SRES}")"
fi fi
elif [[ "${USE_STEABGRIDDB:-1}" == "0" ]]; then
SteamAppId="$(curl -s --connect-timeout 5 -m 10 "https://api.steampowered.com/ISteamApps/GetAppList/v2/" | jq --arg name "${NOSTAPPNAME}" '.applist.apps[] | select(.name == $name) | .appid')"
fi fi
SteamIds=$(jq --arg key "${NOSTAPPNAME}" --arg value "${SteamAppId:-}" '. + {($key): $value}' <<< "${SteamIds:-$(jq -n '{}')}") SteamIds=$(jq --arg key "${NOSTAPPNAME}" --arg value "${SteamAppId:-}" '. + {($key): $value}' <<< "${SteamIds:-$(jq -n '{}')}")
echo "${SteamIds}" > "${cache_file}" echo "${SteamIds}" > "${cache_file}"
@ -129,70 +120,41 @@ getSteamId() {
getSteamGridDBId() { getSteamGridDBId() {
unset SteamGridDBId unset SteamGridDBId
NOSTAPPNAME="$1" NOSTAPPNAME="$1"
if [[ "${USE_STEABGRIDDB:-1}" == "1" ]] && [[ -n "${SGDBAPIKEY}" ]] && [[ -n "${BASESTEAMGRIDDBAPI}" ]] && curl -fs --connect-timeout 5 -m 10 -o /dev/null "${BASESTEAMGRIDDBAPI}"; then SGDBRES=$(curl -Ls -H "Authorization: Bearer ${SGDBAPIKEY}" "${BASESTEAMGRIDDBAPI}/search/autocomplete/${NOSTAPPNAME// /_}")
SGDBRES=$(curl -Ls --connect-timeout 5 -m 10 -H "Authorization: Bearer ${SGDBAPIKEY}" "${BASESTEAMGRIDDBAPI}/search/autocomplete/${NOSTAPPNAME// /_}") if jq -e ".success == true and (.data | length > 0)" <<< "${SGDBRES}" > /dev/null 2>&1; then
if jq -e ".success == true and (.data | length > 0)" <<< "${SGDBRES}" > /dev/null 2>&1; then if jq -e '.data[0].types | contains(["steam"])' <<< "${SGDBRES}" > /dev/null; then
if jq -e '.data[0].types | contains(["steam"])' <<< "${SGDBRES}" > /dev/null; then SteamGridDBTypeSteam=true
SteamGridDBTypeSteam=true else
else SteamGridDBTypeSteam=false
SteamGridDBTypeSteam=false
fi
SteamGridDBId="$(jq '.data[0].id' <<< "${SGDBRES}")"
echo "${SteamGridDBId}"
fi fi
else SteamGridDBId="$(jq '.data[0].id' <<< "${SGDBRES}")"
USE_STEABGRIDDB="0" echo "${SteamGridDBId}"
fi fi
} }
getUserIds() { getUserPath() {
SLUF="${HOME}/.local/share/Steam/config/loginusers.vdf"
if [[ -f "${SLUF}" ]]; then
STUIDS=()
while read -r line; do
if [[ "${line}" =~ ^[[:space:]]*\"([0-9]+)\"$ ]]; then
STUIDS+=("$(extractSteamId32 "${BASH_REMATCH[1]}")")
fi
done < "${SLUF}"
if [[ ${#STUIDS[@]} -gt 0 ]]; then
echo "${STUIDS[@]}"
fi
fi
}
getUserId() {
SLUF="${HOME}/.local/share/Steam/config/loginusers.vdf" SLUF="${HOME}/.local/share/Steam/config/loginusers.vdf"
if [[ -f "${SLUF}" ]]; then if [[ -f "${SLUF}" ]]; then
SLUFUB=false SLUFUB=false
STUID="" STUID64=""
while read -r line; do while read -r line; do
if [[ "${line}" =~ ^[[:space:]]*\"([0-9]+)\"$ ]]; then if [[ "${line}" =~ ^[[:space:]]*\"([0-9]+)\"$ ]]; then
STUIDCUR="${BASH_REMATCH[1]}" STUIDCUR="${BASH_REMATCH[1]}"
SLUFUB=true SLUFUB=true
elif [[ "${line}" == *'"MostRecent"'*'"1"' && ${SLUFUB} = true ]]; then elif [[ "${line}" == *'"MostRecent"'*'"1"' && ${SLUFUB} = true ]]; then
STUID=$(extractSteamId32 "${STUIDCUR}") STUID64="${STUIDCUR}"
break break
elif [[ "${line}" == "}" ]]; then elif [[ "${line}" == "}" ]]; then
SLUFUB=false SLUFUB=false
fi fi
done < "${SLUF}" done < "${SLUF}"
fi if [ -n "${STUID64}" ]; then
if [ -n "${STUID}" ]; then STUID32=$((STUID64 - 76561197960265728))
echo "${STUID}" STUIDPATH="${HOME}/.local/share/Steam/userdata/${STUID32}"
fi if [[ -d "${STUIDPATH}" ]]; then
} if [[ -f "${STUIDPATH}/config/shortcuts.vdf" ]]; then
echo "${STUIDPATH}/config"
getUserPath() { fi
if [[ -n "${1:-}" ]]; then
STUID="$1"
else
STUID="$(getUserId)"
fi
if [ -n "${STUID}" ]; then
STUIDPATH="${HOME}/.local/share/Steam/userdata/${STUID}"
if [[ -d "${STUIDPATH}" ]]; then
if [[ -f "${STUIDPATH}/config/shortcuts.vdf" ]]; then
echo "${STUIDPATH}/config"
fi fi
fi fi
fi fi
@ -216,22 +178,19 @@ listInstalledSteamGames() {
} }
listNonSteamGames() { listNonSteamGames() {
getSteamShortcutHex | while read -r SCVDFE; do getSteamShortcutHex | while read -r SCVDFE; do
jq -n \ jq -n \
--arg id "$(parseSteamShortcutEntryAppID "${SCVDFE}")" \ --arg id "$(parseSteamShortcutEntryAppID "${SCVDFE}")" \
--arg name "$(parseSteamShortcutEntryAppName "${SCVDFE}")" \ --arg name "$(parseSteamShortcutEntryAppName "${SCVDFE}")" \
--arg exe "$(parseSteamShortcutEntryExe "${SCVDFE}")" \ --arg exe "$(parseSteamShortcutEntryExe "${SCVDFE}")" \
--arg dir "$(parseSteamShortcutEntryStartDir "${SCVDFE}")" \ '{id: $id, name: $name, exe: $exe}'
--arg icon "$(parseSteamShortcutEntryIcon "${SCVDFE}")" \ done | jq -s '.'
--arg args "$(parseSteamShortcutEntryLaunchOptions "${SCVDFE}")" \
'{id: $id, name: $name, exe: $exe, dir: $dir, icon: $icon, args: $args}'
done | jq -s '.'
} }
listSteamGames() { listSteamGames() {
( (
jq -r 'map({AppId: .id, SteamAppId: .id, SteamGameId: .id, Name: .name}) | .[] | tostring' <<< "$(listInstalledSteamGames)" jq -r 'map({AppId: .id, SteamAppId: .id, SteamGameId: .id, Name: .name}) | .[] | tostring' <<< "$(listInstalledSteamGames)"
jq -r '.[] | tostring' <<< "$(listNonSteamGames)" | while read -r game; do jq -r '.[] | tostring' <<< "$(listNonSteamGames)" | while read game; do
id=$(jq -r '.id' <<< "${game}") id=$(jq -r '.id' <<< "${game}")
name=$(jq -r '.name' <<< "${game}") name=$(jq -r '.name' <<< "${game}")
jq -r \ jq -r \
@ -249,22 +208,19 @@ convertSteamShortcutAppID() {
} }
convertSteamShortcutHex() { convertSteamShortcutHex() {
# printf "%s" "$1" | xxd -r -p | tr -d '\0'
LC_ALL=C perl -le 'print pack "H*", $ARGV[0]' "$1" | tr -d '\0' LC_ALL=C perl -le 'print pack "H*", $ARGV[0]' "$1" | tr -d '\0'
} }
convertStringToSteamShortcutHex() {
LC_ALL=C perl -e 'print unpack "H*", "$ARGV[0]" . "\x00"' "$(echo "$1" | tr -cd '[:alpha:]')"
}
parseSteamShortcutEntryHex() { parseSteamShortcutEntryHex() {
SHORTCUTSVDFINPUTHEX="$1" # The hex block representing the shortcut SHORTCUTSVDFINPUTHEX="$1" # The hex block representing the shortcut
SHORTCUTSVDFMATCHPATTERN="$2" # The pattern to match against in the block SHORTCUTSVDFMATCHPATTERN="$2" # The pattern to match against in the block
convertSteamShortcutHex "$(getSteamShortcutEntryHex "${SHORTCUTSVDFINPUTHEX}" "${SHORTCUTSVDFMATCHPATTERN}")" convertSteamShortcutHex "$(getSteamShortcutEntryHex "${SHORTCUTSVDFINPUTHEX}" "${SHORTCUTSVDFMATCHPATTERN}")"
} }
parseSteamShortcutEntryAppID() { parseSteamShortcutEntryExe() {
SHORTCUTVDFAPPIDHEXPAT="617070696400" # 'appid' SHORTCUTVDFEXEHEXPAT="000145786500" # 'Exe' ('exe' is 6578650a if we ever need it)
convertSteamShortcutAppID "$(printf "%s" "$1" | grep -oP "${SHORTCUTVDFAPPIDHEXPAT}\K.{8}")" parseSteamShortcutEntryHex "$1" "${SHORTCUTVDFEXEHEXPAT}" | tr -d '"'
} }
parseSteamShortcutEntryAppName() { parseSteamShortcutEntryAppName() {
@ -272,24 +228,9 @@ parseSteamShortcutEntryAppName() {
parseSteamShortcutEntryHex "$1" "${SHORTCUTVDFNAMEHEXPAT}" parseSteamShortcutEntryHex "$1" "${SHORTCUTVDFNAMEHEXPAT}"
} }
parseSteamShortcutEntryExe() { parseSteamShortcutEntryAppID() {
SHORTCUTVDFEXEHEXPAT="000145786500" # 'Exe' ('exe' is 6578650a if we ever need it) SHORTCUTVDFAPPIDHEXPAT="617070696400" # 'appid'
parseSteamShortcutEntryHex "$1" "${SHORTCUTVDFEXEHEXPAT}" | tr -d '"' convertSteamShortcutAppID "$(printf "%s" "$1" | grep -oP "${SHORTCUTVDFAPPIDHEXPAT}\K.{8}")"
}
parseSteamShortcutEntryStartDir() {
SHORTCUTVDFSTARTDIRHEXPAT="0001537461727444697200"
parseSteamShortcutEntryHex "$1" "${SHORTCUTVDFSTARTDIRHEXPAT}" | tr -d '"'
}
parseSteamShortcutEntryIcon() {
SHORTCUTVDFICONHEXPAT="000169636f6e00"
parseSteamShortcutEntryHex "$1" "${SHORTCUTVDFICONHEXPAT}"
}
parseSteamShortcutEntryLaunchOptions() {
SHORTCUTVDFARGHEXPAT="00014c61756e63684f7074696f6e7300" # echo "0001$(convertStringToSteamShortcutHex "LaunchOptions")"
parseSteamShortcutEntryHex "$1" "${SHORTCUTVDFARGHEXPAT}" | tr '\002' '\n' | head -n 1 | tr -d '\000'
} }
parseSteamTargetExe() { parseSteamTargetExe() {
@ -314,7 +255,7 @@ restartSteam() {
} }
downloadImage() { downloadImage() {
if ! curl -Lf# --connect-timeout 5 -m 10 -o "${STCFGPATH}/grid/$2" "$1"; then if ! curl -Lf# -o "${STCFGPATH}/grid/$2" "$1"; then
return 1 return 1
fi fi
} }
@ -331,149 +272,54 @@ downloadImageSteam() {
} }
downloadImageSteamGridDB() { downloadImageSteamGridDB() {
if [[ -n "${SteamGridDBId}" ]]; then SGDBIMGAPI="${BASESTEAMGRIDDBAPI}/$1/game/${SteamGridDBId}?limit=1"
SGDBIMGAPI="${BASESTEAMGRIDDBAPI}/$1/game/${SteamGridDBId}?limit=1" [[ -n "$3" ]] && SGDBIMGAPI+="&$3"
[[ -n "$3" ]] && SGDBIMGAPI+="&$3" [[ -n "$4" ]] && SGDBIMGAPI+="&$4"
[[ -n "$4" ]] && SGDBIMGAPI+="&$4" SGDBIMGRES=$(curl -Ls -H "Authorization: Bearer ${SGDBAPIKEY}" "${SGDBIMGAPI}")
SGDBIMGRES=$(curl -Ls --connect-timeout 5 -m 10 -H "Authorization: Bearer ${SGDBAPIKEY}" "${SGDBIMGAPI}") if jq -e ".success == true and (.data | length > 0)" <<< "${SGDBIMGRES}" > /dev/null 2>&1; then
if jq -e ".success == true and (.data | length > 0)" <<< "${SGDBIMGRES}" > /dev/null 2>&1; then SGDBIMGURL=$(jq -r '.data[0].url' <<< "${SGDBIMGRES}")
SGDBIMGURL=$(jq -r '.data[0].url' <<< "${SGDBIMGRES}") downloadImage "${SGDBIMGURL}" "$2"
downloadImage "${SGDBIMGURL}" "$2" elif [[ -n "$3" ]]; then
elif [[ -n "$3" ]]; then downloadImageSteamGridDB "$1" "$2" "" "$4"
downloadImageSteamGridDB "$1" "$2" "" "$4"
else
return 1
fi
else else
return 1 return 1
fi fi
} }
addGrids() { addGrids() {
getSteamGridDBId "${name_desktop}" > /dev/null if [[ -n "${SGDBAPIKEY}" ]]; then
if [[ "${USE_STEABGRIDDB:-1}" == "0" ]]; then getSteamGridDBId "${name_desktop}" > /dev/null
getSteamId > /dev/null
fi fi
if [[ -n "${SteamGridDBId}" ]] || [[ -n "${SteamAppId}" ]]; then if [[ -n "${SteamGridDBId}" ]]; then
create_new_dir "${STCFGPATH}/grid" create_new_dir "${STCFGPATH}/grid"
downloadImageSteamGridDB "grids" "${NOSTAIDGRID:-0}.jpg" "mimes=image/jpeg" "dimensions=460x215,920x430" || downloadImageSteam "header.jpg" "${NOSTAIDGRID:-0}.jpg" || echo "Failed to load header.jpg" downloadImageSteamGridDB "grids" "${NOSTAIDGRID}.jpg" "mimes=image/jpeg" "dimensions=460x215,920x430" || downloadImageSteam "header.jpg" "${NOSTAIDGRID}.jpg" || echo "Failed to load header.jpg"
downloadImageSteamGridDB "grids" "${NOSTAIDGRID:-0}p.jpg" "mimes=image/jpeg" "dimensions=600x900,660x930" || downloadImageSteam "library_600x900_2x.jpg" "${NOSTAIDGRID:-0}p.jpg" || echo "Failed to load library_600x900_2x.jpg" downloadImageSteamGridDB "grids" "${NOSTAIDGRID}p.jpg" "mimes=image/jpeg" "dimensions=600x900,660x930" || downloadImageSteam "library_600x900_2x.jpg" "${NOSTAIDGRID}p.jpg" || echo "Failed to load library_600x900_2x.jpg"
downloadImageSteamGridDB "heroes" "${NOSTAIDGRID:-0}_hero.jpg" "mimes=image/jpeg" || downloadImageSteam "library_hero.jpg" "${NOSTAIDGRID:-0}_hero.jpg" || echo "Failed to load library_hero.jpg" downloadImageSteamGridDB "heroes" "${NOSTAIDGRID}_hero.jpg" "mimes=image/jpeg" || downloadImageSteam "library_hero.jpg" "${NOSTAIDGRID}_hero.jpg" || echo "Failed to load library_hero.jpg"
downloadImageSteamGridDB "logos" "${NOSTAIDGRID:-0}_logo.png" "mimes=image/png" || downloadImageSteam "logo.png" "${NOSTAIDGRID:-0}_logo.png" || echo "Failed to load logo.png" downloadImageSteamGridDB "logos" "${NOSTAIDGRID}_logo.png" "mimes=image/png" || downloadImageSteam "logo.png" "${NOSTAIDGRID}_logo.png" || echo "Failed to load logo.png"
else else
echo "Game is not found" echo "Game is not found"
fi fi
} }
addEntry() {
if [[ -n "${SCPATH}" ]]; then
if [[ -f "${SCPATH}" ]] ; then
truncate -s-2 "${SCPATH}"
OLDSET="$(grep -aPo '\x00[0-9]\x00\x02appid' "${SCPATH}" | tail -n1 | tr -dc '0-9')"
NEWSET=$((OLDSET + 1))
else
printf '\x00%s\x00' "shortcuts" > "${SCPATH}"
NEWSET=0
fi
NOSTAIDVDFHEXFMT="\x$(awk '{$1=$1}1' FPAT='.{2}' OFS="\\\x" <<< "$NOSTAIDVDFHEX")" # binary-formatted string hex of the above which we actually write out - ex: \xc1\xc2\x5a\xdc
{
printf '\x00%s\x00' "${NEWSET}"
printf '\x02%s\x00%b' "appid" "${NOSTAIDVDFHEXFMT}"
printf '\x01%s\x00%s\x00' "AppName" "${NOSTAPPNAME}"
printf '\x01%s\x00%s\x00' "Exe" "\"${NOSTEXEPATH}\""
printf '\x01%s\x00%s\x00' "StartDir" "\"${NOSTSTDIR}\""
printf '\x01%s\x00%s\x00' "icon" "${NOSTICONPATH}"
printf '\x01%s\x00%s\x00' "ShortcutPath" ""
printf '\x01%s\x00%s\x00' "LaunchOptions" "${NOSTARGS:-}"
printf '\x02%s\x00%b\x00\x00\x00' "IsHidden" "\x00"
printf '\x02%s\x00%b\x00\x00\x00' "AllowDesktopConfig" "\x00"
# These values are now stored in localconfig.vdf under the "Apps" section,
# under a block using the Non-Steam Game Signed 32bit AppID. (i.e., -223056321)
# This is handled by `updateLocalConfigAppsValue` below
#
# Unsure if required, but still write these to the shortcuts.vdf file for consistency
printf '\x02%s\x00%b\x00\x00\x00' "AllowOverlay" "\x00"
printf '\x02%s\x00%b\x00\x00\x00' "OpenVR" "\x00"
printf '\x02%s\x00\x00\x00\x00\x00' "Devkit"
printf '\x01%s\x00\x00' "DevkitGameID"
printf '\x02%s\x00\x00\x00\x00\x00' "DevkitOverrideAppID"
printf '\x02%s\x00\x00\x00\x00\x00' "LastPlayTime"
printf '\x01%s\x00\x00' "FlatpakAppID"
printf '\x00%s\x00' "tags"
printf '\x08\x08\x08\x08'
} >> "${SCPATH}"
fi
}
removeNonSteamGame() {
[[ -n "$1" ]] && appid="$1"
[[ -n "$2" ]] && NOSTSHPATH="$2"
[[ -z "${STUID}" ]] && STUID=$(getUserId)
[[ -z "${STCFGPATH}" ]] && STCFGPATH="$(getUserPath ${STUID})"
if [[ -n "${STCFGPATH}" ]] && [[ -z "${SCPATH}" ]]; then
SCPATH="${STCFGPATH}/shortcuts.vdf"
fi
if [[ -n "${appid}" ]]; then
games=$(listNonSteamGames)
[[ -z "${NOSTSHPATH}" ]] && NOSTSHPATH=$(jq -r --arg id "${appid}" 'map(select(.id == $id)) | first(.[].exe)' <<< "${games}")
if [[ -n "${NOSTSHPATH}" ]]; then
mv "${SCPATH}" "${SCPATH//.vdf}_${PROGNAME}_backup.vdf" 2>/dev/null
jq --arg id "${appid}" 'map(select(.id != $id))' <<< "${games}" | jq -c '.[]' | while read -r game; do
NOSTAIDGRID=$(jq -r '.id' <<< "${game}")
NOSTAPPNAME=$(jq -r '.name' <<< "${game}")
NOSTEXEPATH=$(jq -r '.exe' <<< "${game}")
NOSTSTDIR=$(jq -r '.dir' <<< "${game}")
NOSTICONPATH=$(jq -r '.icon' <<< "${game}")
NOSTARGS=$(jq -r '.args' <<< "${game}")
NOSTAIDVDFHEX=$(bigToLittleEndian $(printf '%08x' "${NOSTAIDGRID}"))
addEntry
done
rm -f "${STCFGPATH}/grid/${appid}.jpg" "${STCFGPATH}/grid/${appid}p.jpg" "${STCFGPATH}/grid/${appid}_hero.jpg" "${STCFGPATH}/grid/${appid}_logo.png"
if [[ -f "${NOSTSHPATH}" ]]; then
isInstallGame=false
for STUIDCUR in $(getUserIds); do
[[ "${STUIDCUR}" == "${STUID}" ]] && continue
STCFGPATH="$(getUserPath ${STUIDCUR})"
SCPATH="${STCFGPATH}/shortcuts.vdf"
if [[ -n "$(getAppId "${NOSTSHPATH}")" ]]; then
isInstallGame=true
break
fi
done
unset STCFGPATH SCPATH
if [[ ${isInstallGame} == false ]]; then
rm "${NOSTSHPATH}"
fi
fi
restartSteam
fi
fi
}
addNonSteamGame() { addNonSteamGame() {
if [[ -z "${STCFGPATH}" ]]; then NOSTAPPNAME="${name_desktop}"
STCFGPATH="$(getUserPath)" NOSTSHPATH="${STEAM_SCRIPTS}/${name_desktop}.sh"
NOSTEXEPATH="\"${NOSTSHPATH}\""
NOSTICONPATH="${PORT_WINE_PATH}/data/img/${name_desktop_png}.png"
if [[ -z "${NOSTSTDIR}" ]]; then
NOSTSTDIR="\"${STEAM_SCRIPTS}\""
fi fi
if [[ -n "${STCFGPATH}" ]] && [[ -z "${SCPATH}" ]]; then STCFGPATH="$(getUserPath)"
if [[ -n "${STCFGPATH}" ]]; then
SCPATH="${STCFGPATH}/shortcuts.vdf" SCPATH="${STCFGPATH}/shortcuts.vdf"
fi fi
if [[ -n "${SCPATH}" ]]; then if [[ -n "${SCPATH}" ]]; then
[[ -z "${NOSTSHPATH}" ]] && NOSTSHPATH="${STEAM_SCRIPTS}/${name_desktop}.sh"
NOSTAPPNAME="${name_desktop}"
NOSTAIDGRID=$(getAppId "${NOSTSHPATH}") NOSTAIDGRID=$(getAppId "${NOSTSHPATH}")
if [[ -z "${NOSTAIDGRID}" ]]; then if [[ -z "${NOSTAIDGRID}" ]]; then
NOSTEXEPATH="${NOSTSHPATH}"
if [[ -z "${NOSTSTDIR}" ]]; then
NOSTSTDIR="${STEAM_SCRIPTS}"
fi
NOSTICONPATH="${PORT_WINE_PATH}/data/img/${name_desktop_png}.png"
NOSTAIDVDF="$(generateShortcutVDFAppId "${NOSTAPPNAME}${NOSTEXEPATH}")" # signed integer AppID, stored in the VDF as hexidecimal - ex: -598031679 NOSTAIDVDF="$(generateShortcutVDFAppId "${NOSTAPPNAME}${NOSTEXEPATH}")" # signed integer AppID, stored in the VDF as hexidecimal - ex: -598031679
NOSTAIDVDFHEX="$(generateShortcutVDFHexAppId "$NOSTAIDVDF")" # 4byte little-endian hexidecimal of above 32bit signed integer, which we write out to the binary VDF - ex: c1c25adc NOSTAIDVDFHEX="$(generateShortcutVDFHexAppId "$NOSTAIDVDF")" # 4byte little-endian hexidecimal of above 32bit signed integer, which we write out to the binary VDF - ex: c1c25adc
NOSTAIDGRID="$(extractSteamId32 "$NOSTAIDVDF")" # unsigned 32bit ingeger version of "$NOSTAIDVDF", which is used as the AppID for Steam artwork ("grids"), as well as for our shortcuts NOSTAIDVDFHEXFMT="\x$(awk '{$1=$1}1' FPAT='.{2}' OFS="\\\x" <<< "$NOSTAIDVDFHEX")" # binary-formatted string hex of the above which we actually write out - ex: \xc1\xc2\x5a\xdc
NOSTAIDGRID="$(generateShortcutGridAppId "$NOSTAIDVDF")" # unsigned 32bit ingeger version of "$NOSTAIDVDF", which is used as the AppID for Steam artwork ("grids"), as well as for our shortcuts
create_new_dir "${STEAM_SCRIPTS}" create_new_dir "${STEAM_SCRIPTS}"
echo "#!/usr/bin/env bash" > "${NOSTSHPATH}" echo "#!/usr/bin/env bash" > "${NOSTSHPATH}"
@ -488,9 +334,47 @@ addNonSteamGame() {
if [[ -f "${SCPATH}" ]] ; then if [[ -f "${SCPATH}" ]] ; then
cp "${SCPATH}" "${SCPATH//.vdf}_${PROGNAME}_backup.vdf" 2>/dev/null cp "${SCPATH}" "${SCPATH//.vdf}_${PROGNAME}_backup.vdf" 2>/dev/null
truncate -s-2 "${SCPATH}"
OLDSET="$(grep -aPo '\x00[0-9]\x00\x02appid' "${SCPATH}" | tail -n1 | tr -dc '0-9')"
NEWSET=$((OLDSET + 1))
else
printf '\x00%s\x00' "shortcuts" > "${SCPATH}"
NEWSET=0
fi fi
addEntry {
printf '\x00%s\x00' "${NEWSET}"
printf '\x02%s\x00%b' "appid" "${NOSTAIDVDFHEXFMT}"
printf '\x01%s\x00%s\x00' "AppName" "${NOSTAPPNAME}"
printf '\x01%s\x00%s\x00' "Exe" "${NOSTEXEPATH}"
printf '\x01%s\x00%s\x00' "StartDir" "${NOSTSTDIR}"
printf '\x01%s\x00%s\x00' "icon" "${NOSTICONPATH}"
printf '\x01%s\x00%s\x00' "ShortcutPath" ""
printf '\x01%s\x00%s\x00' "LaunchOptions" ""
printf '\x02%s\x00%b\x00\x00\x00' "IsHidden" "\x00"
printf '\x02%s\x00%b\x00\x00\x00' "AllowDesktopConfig" "\x00"
# These values are now stored in localconfig.vdf under the "Apps" section,
# under a block using the Non-Steam Game Signed 32bit AppID. (i.e., -223056321)
# This is handled by `updateLocalConfigAppsValue` below
#
# Unsure if required, but still write these to the shortcuts.vdf file for consistency
printf '\x02%s\x00%b\x00\x00\x00' "AllowOverlay" "\x00"
printf '\x02%s\x00%b\x00\x00\x00' "OpenVR" "\x00"
printf '\x02%s\x00\x00\x00\x00\x00' "Devkit"
printf '\x01%s\x00\x00' "DevkitGameID"
printf '\x02%s\x00\x00\x00\x00\x00' "DevkitOverrideAppID"
printf '\x02%s\x00\x00\x00\x00\x00' "LastPlayTime"
printf '\x01%s\x00\x00' "FlatpakAppID"
printf '\x00%s\x00' "tags"
printf '\x08\x08\x08\x08'
} >> "${SCPATH}"
# TODO: замень использование steamgriddb на steam так как сайт steamgriddb у многих без VPN не работает
# а пока просто блочим использование
export DOWNLOAD_STEAM_GRID="0"
if [[ "${DOWNLOAD_STEAM_GRID}" == "1" ]] ; then if [[ "${DOWNLOAD_STEAM_GRID}" == "1" ]] ; then
pw_start_progress_bar_block "${translations[Please wait. downloading covers for]} ${NOSTAPPNAME}" pw_start_progress_bar_block "${translations[Please wait. downloading covers for]} ${NOSTAPPNAME}"

@ -6168,7 +6168,7 @@ portwine_output_yad_shortcut () {
echo "Path=${PORT_SCRIPTS_PATH}/" echo "Path=${PORT_SCRIPTS_PATH}/"
echo "Icon=${PORT_WINE_PATH}/data/img/${name_desktop_png}.png" echo "Icon=${PORT_WINE_PATH}/data/img/${name_desktop_png}.png"
} >> "${PORT_WINE_PATH}/${name_desktop}.desktop" } >> "${PORT_WINE_PATH}/${name_desktop}.desktop"
chmod +x "${PORT_WINE_PATH}/${name_desktop}.desktop" chmod u+x "${PORT_WINE_PATH}/${name_desktop}.desktop"
if [[ "${PW_SHORTCUT_MENU}" == "TRUE" ]] ; then if [[ "${PW_SHORTCUT_MENU}" == "TRUE" ]] ; then
try_remove_file "${HOME}/.local/share/applications/${name_desktop}.desktop" try_remove_file "${HOME}/.local/share/applications/${name_desktop}.desktop"
@ -6308,18 +6308,7 @@ portwine_change_shortcut () {
then PW_SHORTCUT_DESKTOP="TRUE" then PW_SHORTCUT_DESKTOP="TRUE"
else PW_SHORTCUT_DESKTOP="FALSE" else PW_SHORTCUT_DESKTOP="FALSE"
fi fi
if [[ -n $PW_DELETE_STEAM ]]; then PW_SHORTCUT_STEAM="FALSE"
source "${PORT_SCRIPTS_PATH}/add_in_steam.sh"
NOSTSHPATH="${PW_DELETE_SHORTCUT_STEAM[0]//#@_@#/ }"
NOSTAIDGRID=$(getAppId "${NOSTSHPATH}")
if [[ -n "${NOSTSHPATH}" ]] && [[ -n "${NOSTAIDGRID}" ]]; then
PW_SHORTCUT_STEAM="TRUE"
else
PW_SHORTCUT_STEAM="FALSE"
fi
else
PW_SHORTCUT_STEAM="FALSE"
fi
unset name_desktop unset name_desktop
create_name_desktop create_name_desktop
@ -6345,7 +6334,6 @@ portwine_change_shortcut () {
PORTWINE_CHANGE_SHORTCUT=1 PORTWINE_CHANGE_SHORTCUT=1
if [[ $PW_YAD_OUT == 1 ]] ; then if [[ $PW_YAD_OUT == 1 ]] ; then
[[ "$PW_GUI_START" == "NOTEBOOK" ]] && unset PW_YAD_FORM_TAB [[ "$PW_GUI_START" == "NOTEBOOK" ]] && unset PW_YAD_FORM_TAB
PW_SHORTCUT_STEAM="FALSE"
portwine_delete_shortcut portwine_delete_shortcut
restart_pp restart_pp
fi fi
@ -6353,29 +6341,24 @@ portwine_change_shortcut () {
} }
portwine_search_shortcut () { portwine_search_shortcut () {
unset PW_DELETE_SHORTCUT_MENU PW_DELETE_SHORTCUT_STEAM PW_DELETE_SHORTCUT_DESKTOP unset PW_DELETE_SHORTCUT_MENU PW_DELETE_SHORTCUT_DESKTOP
if [[ -n "${portwine_exe}" ]]; then PW_DELETE_MENU="$(grep -il "${portwine_exe}" "${HOME}/.local/share/applications"/*.desktop 2>/dev/null)"
PW_DELETE_MENU="$(grep -il "${portwine_exe}" "${HOME}/.local/share/applications"/*.desktop 2>/dev/null)" read -r -d '' -a PW_DELETE_SHORTCUT_MENU <<< "${PW_DELETE_SHORTCUT_MENU[*]} ${PW_DELETE_MENU// /#@_@#}"
read -r -d '' -a PW_DELETE_SHORTCUT_MENU <<< "${PW_DELETE_SHORTCUT_MENU[*]} ${PW_DELETE_MENU// /#@_@#}"
PW_DELETE_PP="$(grep -il "${portwine_exe}" "${PORT_WINE_PATH}"/*.desktop 2>/dev/null)" PW_DELETE_PP="$(grep -il "${portwine_exe}" "${PORT_WINE_PATH}"/*.desktop 2>/dev/null)"
read -r -d '' -a PW_DELETE_SHORTCUT_MENU <<< "${PW_DELETE_SHORTCUT_MENU[*]} ${PW_DELETE_PP// /#@_@#}" read -r -d '' -a PW_DELETE_SHORTCUT_MENU <<< "${PW_DELETE_SHORTCUT_MENU[*]} ${PW_DELETE_PP// /#@_@#}"
PW_DELETE_STEAM="$(grep -il "${portwine_exe}" "${STEAM_SCRIPTS}"/*.sh 2>/dev/null)" if [[ -d "${HOME}/Desktop" ]] ; then
read -r -d '' -a PW_DELETE_SHORTCUT_STEAM <<< "${PW_DELETE_SHORTCUT_STEAM[*]} ${PW_DELETE_STEAM// /#@_@#}" PW_DELETE_DESKTOP="$(grep -il "${portwine_exe}" "${HOME}/Desktop"/*.desktop 2>/dev/null)"
read -r -d '' -a PW_DELETE_SHORTCUT_DESKTOP <<< "${PW_DELETE_SHORTCUT_DESKTOP[*]} ${PW_DELETE_DESKTOP// /#@_@#}"
if [[ -d "${HOME}/Desktop" ]] ; then fi
PW_DELETE_DESKTOP="$(grep -il "${portwine_exe}" "${HOME}/Desktop"/*.desktop 2>/dev/null)" if [[ -d "${HOME}/Рабочий стол" ]] ; then
read -r -d '' -a PW_DELETE_SHORTCUT_DESKTOP <<< "${PW_DELETE_SHORTCUT_DESKTOP[*]} ${PW_DELETE_DESKTOP// /#@_@#}" PW_DELETE_DESKTOP="$(grep -il "${portwine_exe}" "${HOME}/Рабочий стол"/*.desktop 2>/dev/null)"
fi read -r -d '' -a PW_DELETE_SHORTCUT_DESKTOP <<< "${PW_DELETE_SHORTCUT_DESKTOP[*]} ${PW_DELETE_DESKTOP// /#@_@#}"
if [[ -d "${HOME}/Рабочий стол" ]] ; then fi
PW_DELETE_DESKTOP="$(grep -il "${portwine_exe}" "${HOME}/Рабочий стол"/*.desktop 2>/dev/null)" if [[ $(xdg-user-dir DESKTOP) ]] ; then
read -r -d '' -a PW_DELETE_SHORTCUT_DESKTOP <<< "${PW_DELETE_SHORTCUT_DESKTOP[*]} ${PW_DELETE_DESKTOP// /#@_@#}" PW_DELETE_DESKTOP="$(grep -il "${portwine_exe}" "$(xdg-user-dir DESKTOP)"/*.desktop 2>/dev/null)"
fi read -r -d '' -a PW_DELETE_SHORTCUT_DESKTOP <<< "${PW_DELETE_SHORTCUT_DESKTOP[*]} ${PW_DELETE_DESKTOP// /#@_@#}"
if [[ $(xdg-user-dir DESKTOP) ]] ; then
PW_DELETE_DESKTOP="$(grep -il "${portwine_exe}" "$(xdg-user-dir DESKTOP)"/*.desktop 2>/dev/null)"
read -r -d '' -a PW_DELETE_SHORTCUT_DESKTOP <<< "${PW_DELETE_SHORTCUT_DESKTOP[*]} ${PW_DELETE_DESKTOP// /#@_@#}"
fi
fi fi
} }
@ -6388,11 +6371,6 @@ portwine_delete_shortcut () {
for delete_shortcut in "${PW_DELETE_SHORTCUT_MENU[@]}" "${PW_DELETE_SHORTCUT_DESKTOP[@]}" ; do for delete_shortcut in "${PW_DELETE_SHORTCUT_MENU[@]}" "${PW_DELETE_SHORTCUT_DESKTOP[@]}" ; do
rm -f "${delete_shortcut//#@_@#/ }" rm -f "${delete_shortcut//#@_@#/ }"
done done
if [[ "${PW_SHORTCUT_STEAM}" == "FALSE" ]] && [[ -n "${NOSTSHPATH}" ]] && [[ -n "${NOSTAIDGRID}" ]]; then
source "${PORT_SCRIPTS_PATH}/add_in_steam.sh"
removeNonSteamGame "${NOSTAIDGRID}" "${NOSTSHPATH}"
fi
} }
portwine_missing_shortcut () { portwine_missing_shortcut () {
@ -6987,7 +6965,7 @@ gui_edit_db_file () {
} }
gui_open_scripts_from_backup () { gui_open_scripts_from_backup () {
[[ -d "${PORT_WINE_TMP_PATH}/scripts_backup/" ]] && cd "${PORT_WINE_TMP_PATH}/scripts_backup/" || cd "$HOME" cd "${PORT_WINE_TMP_PATH}/scripts_backup/" || fatal
PW_SCRIPT_FROM_BACKUP=$("${pw_yad}" --file --width=650 --height=500 \ PW_SCRIPT_FROM_BACKUP=$("${pw_yad}" --file --width=650 --height=500 \
--window-icon="$PW_GUI_ICON_PATH/portproton.svg" --title "SCRIPTS FROM BACKUP" --file-filter="backup_scripts|scripts_v*.tar.gz" 2>/dev/null ) --window-icon="$PW_GUI_ICON_PATH/portproton.svg" --title "SCRIPTS FROM BACKUP" --file-filter="backup_scripts|scripts_v*.tar.gz" 2>/dev/null )
YAD_STATUS="$?" YAD_STATUS="$?"

@ -1,26 +0,0 @@
#!/usr/bin/env bash
# Author: chal55rus
# type: games
# name: Fractured Online (ENG)
# image: fracturedonline
# info_en: Fractured Online is the first open-world sandbox MMORPG mixing action combat with fully interactable environments, appealing equally to lovers of competitive and cooperative gameplay. Jump right into the fray from day one. Defeat your enemies through your own skill and cleverness, not equipment or level. Gather resources, craft, trade and venture into legendary travels as a solitary hero, or start a settlement with your guild and grow it into the next empire.
# info_ru: Fractured Online — это первая массовая многопользовательская ролевая онлайн-игра с открытым миром, сочетающая динамичные сражения с полностью интерактивным окружением. Она одинаково понравится любителям соревновательного и кооперативного игрового процесса. С самого первого дня погрузитесь в бой. Побеждайте врагов благодаря собственным навыкам и смекалке, а не снаряжению или уровню. Собирайте ресурсы, создавайте предметы, торгуйте и отправляйтесь в легендарные путешествия в одиночку или создайте поселение со своей гильдией и превратите его в следующую империю.
########################################################################
export PW_PREFIX_NAME="FRACTURED_ONLINE"
export LAUNCH_PARAMETERS="/S"
export PW_AUTOINSTALL_EXE="${PW_USER_TEMP}/fractured-online-setup.exe"
export PORTWINE_CREATE_SHORTCUT_NAME="Fractured Online"
start_portwine
if try_download "https://assets.fracturedmmo.com/clients/3f990010d1afb2cabadc44c6c849116c/fractured-online-setup.exe" "${PW_AUTOINSTALL_EXE}" no_mirror
then
pw_start_progress_bar_install_game "Fractured Online."
pw_run "${PW_AUTOINSTALL_EXE}"
portwine_exe="$WINEPREFIX/drive_c/Program Files/Fractured Online/FracturedOnline.exe"
try_remove_file "${PW_AUTOINSTALL_EXE}"
try_remove_file "${portwine_exe}.ppdb"
kill_portwine
pw_stop_progress_bar
portwine_create_shortcut
fi
stop_portwine

@ -1,25 +0,0 @@
#!/usr/bin/env bash
# Author: chal55rus
# type: games
# name: Last Chaos
# image: lastchaos
# info_en: Last Chaos is a classic MMORPG with six classes, castle sieges, a Korean grind and kilometers of dungeons. The confrontation between Apollo and Eres is gaining momentum, so hurry up to take one of the sides.
# info_ru: Last Chaos классическая MMORPG с шестью классами, осадами замков, корейским гриндом и километрами подземелий. Противостояние Апполона и Эреса набирает обороты, так что спешите принять одну из сторон.
########################################################################
export PW_PREFIX_NAME="LAST_CHAOS"
export PW_AUTOINSTALL_EXE="${PW_USER_TEMP}/Last Chaos.zip"
export PORTWINE_CREATE_SHORTCUT_NAME="Last Chaos"
start_portwine
if try_download "https://last-chaos.ru/download/Last%20Chaos.zip" "${PW_AUTOINSTALL_EXE}" no_mirror
then
pw_start_progress_bar_install_game "Last Chaos."
"$pw_7z" x -y "${PW_AUTOINSTALL_EXE}" -o"${WINEPREFIX}/drive_c/Program Files/"
portwine_exe="${WINEPREFIX}/drive_c/Program Files/Last Chaos/LC.exe"
try_remove_file "${PW_AUTOINSTALL_EXE}"
try_remove_file "${portwine_exe}.ppdb"
kill_portwine
pw_stop_progress_bar
portwine_create_shortcut
fi
stop_portwine

@ -4,10 +4,9 @@ credits_devel () { echo "
Boria138 Boria138
Vano Majukin Vano Majukin
Eljeyna Eljeyna
minergenon (chal55rus) chal55rus
SDR SDR
Mels Mels
alex2844
Cefeiko Cefeiko
Dezert1r Dezert1r
Taz_mania Taz_mania

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#Author: Castro-Fidel (linux-gaming.ru) #Author: Castro-Fidel (linux-gaming.ru)
#SCRIPTS_NEXT_VERSION=2386 #SCRIPTS_NEXT_VERSION=2385
#SCRIPTS_STABLE_VERSION=2385 #SCRIPTS_STABLE_VERSION=2385
######################################################################## ########################################################################
export AI_TOP_GAMES="PW_LGC PW_VKPLAY PW_EPIC PW_BATTLE_NET PW_WORLD_OF_SEA_BATTLE PW_RUSSIAN_FISHING PW_HO_YO_PLAY PW_FARLIGHT84 PW_WARFRAME PW_WGC PW_UBISOFT" export AI_TOP_GAMES="PW_LGC PW_VKPLAY PW_EPIC PW_BATTLE_NET PW_WORLD_OF_SEA_BATTLE PW_RUSSIAN_FISHING PW_HO_YO_PLAY PW_FARLIGHT84 PW_WARFRAME PW_WGC PW_UBISOFT"