Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/launcher_main/neo_case_heal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// Heal hack :: fix poisoned installations

// Binaries the engine loads by exact mixed-case name.
// Keep this list in sync with src/devtools/check_depot_casing.sh.
// Keep this list in sync with tools/check-depot-casing.sh.
// It's hacky but it works, and should be harmless to leave in
// clearly marked, use `git blame` to find the commit to revert.
static const char *k_pszCanonicalBinaryPaths[] =
Expand Down
64 changes: 64 additions & 0 deletions tools/check-depot-casing.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/bin/sh
# ████
# ████████ ██████████ ▓▓▓▓
# ████████████ ███████████ ▓▓▓▓▓▓
# █████░░░█████░ █████░░░░░░░ ▓▓▓▓▓▓░
# █████░ █████░ █████░ ▓▓▓▓░░
# █████░ █████░ █████░ ░░░░
# █████░ █████░ ██████████ █████
# █████░ █████░ ██████████░ █████░
# ░░░░░ █████░ ░░░░░░░░░░ ████░░░
# █████░ ███░░░
# ░░░░░ ░░░
#
# N E O T O K Y O ; R E B U I L D

# Checks a depot staging tree for engine binaries staged under the wrong
# file name casing. The engine loads these binaries by exact mixed-case
# name, and Steam never repairs casing on installs, so a miscased file
# in one upload breaks fresh Linux installs until the next full fix.
# Run this against the staging root before every steamcmd upload:
#
# ./check-depot-casing.sh /path/to/staging/root
#
# Exits 0 when clean, 1 with one line per offending file otherwise.
# Keep the list below in sync with src/launcher_main/neo_case_heal.cpp
# (PR #2055, the launcher-side repair for already-broken installs).

# Show the logo when running in a terminal. The helper lives next to this
# script in the repo; a standalone copy of this script skips it silently.
[ -f "$(dirname "$0")/nt-logo.sh" ] && . "$(dirname "$0")/nt-logo.sh" && nt_logo

root="${1:?usage: check-depot-casing.sh <staging-root>}"

canonical_paths="
bin/GameUI.so
bin/ServerBrowser.so
bin/libMiles.so
bin/libTelemetryX64.so
bin/libTelemetryX86.so
bin/linux64/GameUI.so
bin/linux64/ServerBrowser.so
"

status=0
for canon in $canonical_paths; do
dir=$(dirname "$canon")
want=$(basename "$canon")
want_lower=$(printf '%s' "$want" | tr '[:upper:]' '[:lower:]')
[ -d "$root/$dir" ] || continue
for path in "$root/$dir"/*; do
[ -e "$path" ] || continue
have=$(basename "$path")
have_lower=$(printf '%s' "$have" | tr '[:upper:]' '[:lower:]')
if [ "$have_lower" = "$want_lower" ] && [ "$have" != "$want" ]; then
echo "WRONG CASING: $dir/$have (expected $dir/$want)" >&2
status=1
fi
done
done

if [ "$status" -eq 0 ]; then
echo "Depot casing OK."
fi
exit $status
75 changes: 75 additions & 0 deletions tools/fix-linux-casing.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/bash
# ████
# ████████ ██████████ ▓▓▓▓
# ████████████ ███████████ ▓▓▓▓▓▓
# █████░░░█████░ █████░░░░░░░ ▓▓▓▓▓▓░
# █████░ █████░ █████░ ▓▓▓▓░░
# █████░ █████░ █████░ ░░░░
# █████░ █████░ ██████████ █████
# █████░ █████░ ██████████░ █████░
# ░░░░░ █████░ ░░░░░░░░░░ ████░░░
# █████░ ███░░░
# ░░░░░ ░░░
#
# N E O T O K Y O ; R E B U I L D

# Repairs an NT;RE Linux install whose engine binaries have fully
# lowercased file names. The engine loads these binaries by exact
# mixed-case name, and Steam neither renames files on disk nor fails
# verification over casing, so a broken install stays broken until the
# files are renamed. Run from (or point at) the game install root, the
# directory that contains bin/ and neo/:
#
# ./fix-linux-casing.sh ~/.local/share/Steam/steamapps/common/NEOTOKYOREBUILD
#
# Safe to run repeatedly. Prints every change it makes.
# The canonical list matches src/launcher_main/neo_case_heal.cpp
# (PR #2055, the launcher-side repair that runs at every startup).

set -u

# Show the logo when running in a terminal. The helper lives next to this
# script in the repo; a standalone copy of this script skips it silently.
[ -f "$(dirname "$0")/nt-logo.sh" ] && . "$(dirname "$0")/nt-logo.sh" && nt_logo

root="${1:-.}"

if [ ! -d "$root/bin" ] || [ ! -d "$root/neo" ]; then
echo "error: $root does not look like an NT;RE install root (needs bin/ and neo/)" >&2
exit 2
fi

canonical_paths=(
"bin/GameUI.so"
"bin/ServerBrowser.so"
"bin/libMiles.so"
"bin/libTelemetryX64.so"
"bin/libTelemetryX86.so"
"bin/linux64/GameUI.so"
"bin/linux64/ServerBrowser.so"
)

repairs=0
for canon in "${canonical_paths[@]}"; do
lower=$(printf '%s' "$canon" | tr '[:upper:]' '[:lower:]')
[ "$lower" = "$canon" ] && continue
lower_path="$root/$lower"
canon_path="$root/$canon"
[ -e "$lower_path" ] || [ -L "$lower_path" ] || continue

if [ ! -e "$canon_path" ] && [ ! -L "$canon_path" ]; then
mv "$lower_path" "$canon_path" && echo "renamed: $lower -> $canon" && repairs=$((repairs+1))
elif [ "$lower_path" -nt "$canon_path" ]; then
# The lowercased twin is newer, so Steam wrote it last and it
# carries the current content. Replace the canonical file.
mv -f "$lower_path" "$canon_path" && echo "replaced with newer: $canon" && repairs=$((repairs+1))
else
rm -f "$lower_path" && echo "removed stale twin: $lower" && repairs=$((repairs+1))
fi
done

if [ "$repairs" -eq 0 ]; then
echo "Nothing to repair. File name casing is already correct."
else
echo "Done. $repairs file(s) repaired."
fi
44 changes: 44 additions & 0 deletions tools/nt-logo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/sh
# Prints the shadowed NT;RE logo, in color when the terminal supports it.
# Prints nothing when stdout is not a terminal, so piped and logged output
# stays clean. POSIX sh so both bash and sh scripts can source it:
#
# [ -f "$(dirname "$0")/nt-logo.sh" ] && . "$(dirname "$0")/nt-logo.sh" && nt_logo
#
# Running this file directly also prints the logo.

nt_logo() {
[ -t 1 ] || return 0
# Print once per process tree: child scripts inherit the mark, so a
# wrapper like toolbox.sh shows the logo and the tools it runs skip it.
[ "${NT_LOGO_SHOWN:-}" = 1 ] && return 0
NT_LOGO_SHOWN=1
export NT_LOGO_SHOWN
r=''; s=''; b=''; x=''
if [ -z "${NO_COLOR:-}" ] && [ "${TERM:-dumb}" != dumb ]; then
r='\033[31m' # red semicolon dot
s='\033[2m' # dim drop shadow
b='\033[1m' # bold title
x='\033[0m'
fi
printf '%b\n' \
" ████" \
" ████████ ██████████ ${r}▓▓▓▓${x}" \
" ████████████ ███████████ ${r}▓▓▓▓▓▓${x}" \
" █████${s}░░░${x}█████${s}░${x} █████${s}░░░░░░░${x} ${r}▓▓▓▓▓▓${x}${s}░${x}" \
" █████${s}░${x} █████${s}░${x} █████${s}░${x} ${r}▓▓▓▓${x}${s}░░${x}" \
" █████${s}░${x} █████${s}░${x} █████${s}░${x} ${s}░░░░${x}" \
" █████${s}░${x} █████${s}░${x} ██████████ █████" \
" █████${s}░${x} █████${s}░${x} ██████████${s}░${x} █████${s}░${x}" \
" ${s}░░░░░${x} █████${s}░${x} ${s}░░░░░░░░░░${x} ████${s}░░░${x}" \
" █████${s}░${x} ███${s}░░░${x}" \
" ${s}░░░░░${x} ${s}░░░${x}" \
"" \
" ${b} N E O T O K Y O ; R E B U I L D${x}" \
""
}

# Print right away when executed instead of sourced.
case "$0" in
*nt-logo.sh) nt_logo ;;
esac
68 changes: 68 additions & 0 deletions tools/toolbox.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/bin/bash
# ████
# ████████ ██████████ ▓▓▓▓
# ████████████ ███████████ ▓▓▓▓▓▓
# █████░░░█████░ █████░░░░░░░ ▓▓▓▓▓▓░
# █████░ █████░ █████░ ▓▓▓▓░░
# █████░ █████░ █████░ ░░░░
# █████░ █████░ ██████████ █████
# █████░ █████░ ██████████░ █████░
# ░░░░░ █████░ ░░░░░░░░░░ ████░░░
# █████░ ███░░░
# ░░░░░ ░░░
#
# N E O T O K Y O ; R E B U I L D

# Single entry point for the NT;RE devtools. Shows the tools as a numbered
# menu, prompts for the one path argument, and runs the selection.
#
# ./toolbox.sh
#
# To plug a new tool into the menu, add one line to the table below:
# "script name|path prompt|default path|one-line description". The script
# must live next to this file and take a single path argument.

set -u

here="$(cd "$(dirname "$0")" && pwd)"

[ -t 0 ] || { echo "error: toolbox.sh is an interactive menu, run it from a terminal" >&2; exit 2; }

[ -f "$here/nt-logo.sh" ] && . "$here/nt-logo.sh" && nt_logo

tools=(
"check-depot-casing.sh|Staging root to check|.|Check a depot staging tree for wrongly cased binaries"
"fix-linux-casing.sh|Install root to repair|.|Repair a Linux install's binary file name casing"
)

while :; do
echo
echo "Tools:"
for i in "${!tools[@]}"; do
IFS='|' read -r script _ _ desc <<< "${tools[$i]}"
printf ' %d) %-24s %s\n' "$((i + 1))" "$script" "$desc"
done
echo " Q) quit (default)"
read -rp "Select [# or Q]: " choice || exit 0

case "$choice" in
''|q|Q)
exit 0
;;
*[!0-9]*)
echo "Pick a tool number or Q." >&2
;;
*)
idx=$(( choice - 1 ))
if [ "$idx" -lt 0 ] || [ "$idx" -ge "${#tools[@]}" ]; then
echo "No tool number $choice." >&2
continue
fi
IFS='|' read -r script prompt default _ <<< "${tools[$idx]}"
read -rp "$prompt [$default]: " arg || exit 0
echo
"$here/$script" "${arg:-$default}"
echo "($script exited $?)"
;;
esac
done