#!/usr/bin/env bash # Installer for the Embarrassed Shina-chan Linux/Proton fix pack. # # Modifies only files inside the game folder and the game's Proton prefix; no # game binaries ship with this repo. Every modified file is backed up # (*.orig / user.reg.bak-*) so uninstall.sh can revert. # # Usage: # ./install.sh [/path/to/steamapps/common/Embarrassed Shina-chan~ .../] # If no path is given it tries common Steam library locations. set -euo pipefail HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" APPID=2326780 find_game() { local c for c in \ "$HOME/.steam/steam/steamapps/common/Embarrassed Shina-chan~ the Naked Wandering College Girl" \ "$HOME/.local/share/Steam/steamapps/common/Embarrassed Shina-chan~ the Naked Wandering College Girl"; do [ -f "$c/data/kmyCore.dll" ] && { echo "$c"; return 0; } done # scan libraryfolders.vdf for extra libraries local vdf="$HOME/.steam/steam/steamapps/libraryfolders.vdf" [ -f "$vdf" ] || vdf="$HOME/.local/share/Steam/steamapps/libraryfolders.vdf" if [ -f "$vdf" ]; then local lib g while IFS= read -r lib; do g="$lib/steamapps/common/Embarrassed Shina-chan~ the Naked Wandering College Girl" [ -f "$g/data/kmyCore.dll" ] && { echo "$g"; return 0; } done < <(grep -oE '"path"[[:space:]]*"[^"]+"' "$vdf" | sed -E 's/.*"([^"]+)"$/\1/') fi return 1 } GAME_ROOT="${1:-$(find_game || true)}" if [ -z "${GAME_ROOT:-}" ] || [ ! -f "$GAME_ROOT/data/kmyCore.dll" ]; then echo "!! Could not locate the game. Pass its folder explicitly:" echo " ./install.sh \"/path/to/steamapps/common/Embarrassed Shina-chan~ the Naked Wandering College Girl\"" exit 1 fi echo "Game folder: $GAME_ROOT" echo # check every required tool up front so the install never stops halfway through. # all of these are needed for a working game: gcc builds the runtime hook, and # dotnet builds the IL patcher for the plugin-path fix, without which no asset # plugins load and the game stays a grey screen. missing="" for tool in gcc patch od dd md5sum dotnet; do command -v "$tool" >/dev/null 2>&1 || missing="$missing $tool" done if [ -n "$missing" ]; then echo "!! missing required tools:$missing" echo " gcc - builds the runtime hook (fix 4)" echo " patch/od/dd/md5sum - apply and verify the byte/shader patches (fixes 1-3)" echo " dotnet - the .NET SDK, builds the IL patcher for the plugin-path" echo " fix (fix 2); needs network access once to fetch Mono.Cecil" exit 1 fi command -v python3 >/dev/null 2>&1 || \ echo " note: python3 not found, only needed for the optional Wayland fix 5" # LD_PRELOAD treats colons and spaces as separators, so a repo path containing # them would silently break the runtime hook case "$HERE" in *' '*|*:*) echo "!! this repo's path contains a space or ':', which LD_PRELOAD cannot handle." echo " Move the repo, e.g.: mv \"$HERE\" ~/shina-linux-patch and re-run." exit 1;; esac echo "[1/5] kmyCore disk-FS" bash "$HERE/patches/01-kmycore-diskfs.sh" "$GAME_ROOT" echo "[2/5] bakinplayer plugin path" bash "$HERE/patches/02-pluginpath/apply.sh" "$GAME_ROOT" echo "[3/5] shader vin_* keep-alive" SH="$GAME_ROOT/data/lib/sysresource/shader/include/v2_vpcommon.cgh" SHPATCH="$HERE/patches/03-shader-vin-keepalive.patch" if grep -q "VIN_KEEPALIVE" "$SH"; then echo "== Fix 3: already applied" else # dry-run first; a partially applied patch would leave every shader # referencing an undefined VIN_KEEPALIVE if ! patch -p1 -d "$GAME_ROOT" -s -f --dry-run < "$SHPATCH" >/dev/null 2>&1; then echo "!! Fix 3: shader source does not match this patch (different game build?)." echo "!! Not touching it. v2_vpcommon.cgh left unmodified." exit 3 fi [ -f "$SH.orig" ] || cp "$SH" "$SH.orig" patch -p1 -d "$GAME_ROOT" -s -f < "$SHPATCH" echo "== Fix 3: shader patched, backup at v2_vpcommon.cgh.orig" fi echo "[4/5] runtime hook (VAO fix + audio-deadlock cap + IBL LUT)" HOOKDIR="$HERE/patches/04-runtime-hook" IBL_SRC="$HOOKDIR/ibl_brdf_lut.bmp" # the game's per-launch shader/texture extraction lives in the Proton prefix: TMPBASE="$(cd "$GAME_ROOT/../.." && pwd)/compatdata/$APPID/pfx/drive_c/users/steamuser/AppData/Local/Temp/bakin_engine_tmp" # both paths end up inside C string literals, so refuse characters that break them for p in "$IBL_SRC" "$TMPBASE"; do case "$p" in *'"'*|*'\'*) echo "!! cannot embed a path containing \" or \\ into the hook: $p"; exit 1;; esac done sed_esc() { printf '%s' "$1" | sed 's/[&|]/\\&/g'; } sed -e "s|@IBL_SRC@|$(sed_esc "$IBL_SRC")|g" -e "s|@TMPBASE@|$(sed_esc "$TMPBASE")|g" \ "$HOOKDIR/bakin_minimal.c" > "$HOOKDIR/bakin_minimal.installed.c" gcc -O2 -shared -fPIC -o "$HOOKDIR/bakin_minimal.so" "$HOOKDIR/bakin_minimal.installed.c" -ldl -lpthread echo "== built $HOOKDIR/bakin_minimal.so" echo "[5/5] launcher" HOOK_SO="$HOOKDIR/bakin_minimal.so" LAUNCHER="$HERE/launcher.installed.sh" sed "s|@HOOK_SO@|$(sed_esc "$HOOK_SO")|g" "$HERE/launcher.sh" > "$LAUNCHER" chmod +x "$LAUNCHER" echo echo "======================================================================" echo "Done. Two manual steps remain:" echo echo "1) Steam -> Embarrassed Shina-chan -> Properties -> Launch Options:" echo " \"$LAUNCHER\" %command%" echo echo "2) Wayland desktops only (keyboard focus). Fully close the game, then:" echo " bash \"$HERE/patches/05-wayland-keyboard.sh\" \"$GAME_ROOT\"" echo " (harmless to skip on X11.)" echo echo "Then launch from Steam. To revert everything: ./uninstall.sh \"$GAME_ROOT\"" echo "======================================================================"