#!/bin/bash # ============================================================================= # Popcorn's Pantheon - Season I: Odin's Trial # One-click Valheim modpack installer for macOS. # # Double-click me (right-click -> Open the first time to get past # Gatekeeper). Installs BepInEx + the pinned client mods into the Steam # Valheim install, then drops a "Popcorn's Pantheon" launcher on the # Desktop that starts Valheim modded (BepInEx via Rosetta/x86_64). # Re-running is safe (repair/update). # ============================================================================= CONNECT_ADDR="100.99.102.101:2456" PASSWORD="ravenrock" UA="PopcornsPantheon-Installer/1.0" say_step() { printf '\n==> %s\n' "$1"; } say_ok() { printf ' %s\n' "$1"; } finish() { printf '\n' if [ -t 0 ]; then read -r -p "Press Return to close this window... " _ ; fi exit "$1" } fail() { printf '\nERROR: %s\n' "$1"; finish 1; } printf '\n' printf " Popcorn's Pantheon - Season I: Odin's Trial\n" printf ' Valheim modpack installer for macOS\n' # ---- 1. Find the Valheim install -------------------------------------------- say_step 'Looking for your Valheim install...' STEAM_DIR="$HOME/Library/Application Support/Steam" CANDIDATES=("$STEAM_DIR/steamapps/common/Valheim") VDF="$STEAM_DIR/steamapps/libraryfolders.vdf" if [ -f "$VDF" ]; then while IFS= read -r lib; do CANDIDATES+=("$lib/steamapps/common/Valheim") done < <(sed -n 's/.*"path"[[:space:]]*"\([^"]*\)".*/\1/p' "$VDF") fi VALHEIM="" for c in "${CANDIDATES[@]}"; do if [ -d "$c/Valheim.app" ]; then VALHEIM="$c"; break; fi done if [ -z "$VALHEIM" ]; then printf '\nCould not find Valheim.\n' printf 'Install Valheim from Steam first, then run this installer again.\n' printf 'Places checked:\n' for c in "${CANDIDATES[@]}"; do printf ' - %s\n' "$c"; done finish 1 fi say_ok "Found Valheim at: $VALHEIM" TMP=$(mktemp -d "${TMPDIR:-/tmp}/pantheon.XXXXXX") || fail 'Could not create a temp folder.' trap 'rm -rf "$TMP"' EXIT # Downloads a pinned Thunderstore package zip; echoes the zip path. fetch() { local ns="$1" name="$2" ver="$3" zip="$TMP/$1-$2.zip" curl -fsSL --retry 3 -A "$UA" -o "$zip" \ "https://thunderstore.io/package/download/$ns/$name/$ver/" || return 1 printf '%s' "$zip" } FAILED="" TOTAL=9 # ---- 2. BepInEx (the framework) -> the Valheim game ROOT -------------------- say_step "[1/$TOTAL] denikson-BepInExPack_Valheim v5.4.2333 (mod framework)" ZIP=$(fetch denikson BepInExPack_Valheim 5.4.2333) \ || fail 'Could not download BepInEx. Check your internet connection and try again.' EX="$TMP/bepinex" mkdir -p "$EX" unzip -qo "$ZIP" -d "$EX" || fail 'Could not unpack BepInEx.' [ -d "$EX/BepInExPack_Valheim" ] || fail 'Unexpected BepInEx package layout.' # Inner folder contents -> game root: BepInEx/, doorstop bits, winhttp.dll, # and the macOS start_game_bepinex.sh launcher script. cp -Rf "$EX/BepInExPack_Valheim/." "$VALHEIM/" || fail 'Could not copy BepInEx into the game folder.' chmod +x "$VALHEIM/start_game_bepinex.sh" 2>/dev/null say_ok 'BepInEx installed into the game folder' # ---- 3. The pinned mods -> BepInEx/plugins// -------------------- MODS=" ValheimModding|JsonDotNET|13.0.4 ValheimModding|YamlDotNet|16.3.1 ValheimModding|Jotunn|2.29.0 shudnal|ConditionalConfigSync|1.0.0 Smoothbrain|CreatureLevelAndLootControl|4.6.4 shudnal|TradersExtended|2.0.0 RandyKnapp|EpicLoot|0.12.15 VentureValheim|World_Advancement_Progression|0.3.14 " i=1 for spec in $MODS; do i=$((i + 1)) ns="${spec%%|*}"; rest="${spec#*|}"; name="${rest%%|*}"; ver="${rest#*|}" label="$ns-$name v$ver" say_step "[$i/$TOTAL] $label" if ! zip=$(fetch "$ns" "$name" "$ver"); then printf ' Download failed.\n' FAILED="$FAILED $label" continue fi ex="$TMP/$ns-$name" mkdir -p "$ex" if ! unzip -qo "$zip" -d "$ex"; then printf ' Unpack failed.\n' FAILED="$FAILED $label" continue fi # Everything except manifest.json / icon.png / *.md goes into the plugin # folder (delete-then-copy so re-runs repair/update). rm -f "$ex/manifest.json" "$ex/icon.png" find "$ex" -maxdepth 1 -iname '*.md' -exec rm -f {} + dest="$VALHEIM/BepInEx/plugins/$ns-$name" rm -rf "$dest" mkdir -p "$dest" if ! cp -Rf "$ex/." "$dest/"; then printf ' Copy failed.\n' FAILED="$FAILED $label" continue fi say_ok "Installed to BepInEx/plugins/$ns-$name" done # ---- 4. The Desktop launcher ------------------------------------------------ # Mac must launch through start_game_bepinex.sh (NOT plain Steam Play) and # under x86_64/Rosetta so the x64 doorstop injects into Unity. say_step "Creating the 'Popcorn's Pantheon' launcher on your Desktop..." LAUNCHER="$HOME/Desktop/Popcorn's Pantheon.command" cat > "$LAUNCHER" </dev/null say_ok "Launcher created: ~/Desktop/Popcorn's Pantheon.command" if [ -n "$FAILED" ]; then printf '\nSome packages failed:%s\n' "$FAILED" printf 'Check your internet connection and run this installer again - re-running is safe.\n' finish 1 fi printf '\n=================================================================\n' printf ' Done! The realm awaits.\n' printf '=================================================================\n\n' printf ' 1. Open Steam and make sure you are logged in.\n' printf " 2. Double-click 'Popcorn's Pantheon' on your Desktop to launch\n" printf ' Valheim modded. (On Mac you MUST launch via that icon - not\n' printf ' the plain Steam Play button.)\n' printf ' 3. Select your character, then: Join Game -> Join by IP\n' printf ' Address: %s\n' "$CONNECT_ADDR" printf ' Password: %s\n' "$PASSWORD" printf '\n (Early access: you must be joined to the Tailscale network first.)\n' finish 0