├── .gitignore ├── LICENSE ├── README.md └── open-unity.sh /.gitignore: -------------------------------------------------------------------------------- 1 | ### macOS ### 2 | # General 3 | .DS_Store 4 | .AppleDouble 5 | .LSOverride 6 | 7 | # Icon must end with two \r 8 | Icon 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | .com.apple.timemachine.donotpresent 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | 29 | ### Windows ### 30 | # Windows thumbnail cache files 31 | Thumbs.db 32 | Thumbs.db:encryptable 33 | ehthumbs.db 34 | ehthumbs_vista.db 35 | 36 | # Dump file 37 | *.stackdump 38 | 39 | # Folder config file 40 | [Dd]esktop.ini 41 | 42 | # Recycle Bin used on file shares 43 | $RECYCLE.BIN/ 44 | 45 | # Windows Installer files 46 | *.cab 47 | *.msi 48 | *.msix 49 | *.msm 50 | *.msp 51 | 52 | # Windows shortcuts 53 | *.lnk 54 | 55 | *.log 56 | *~ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Andreia Gaita 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # open-unity.sh 2 | 3 | This bash script opens a Unity project from the command line. I wrote this because I needed to redirect Unity's logs to a known, sane place, and not lose them every time Unity crashed or restarted. It kinda grew from there. 4 | 5 | It can autodetect what the current build target is for a project, what Unity version is it set to, what Unity versions you have installed on your system, and it will try its best to open a project with the correct settings. It will also redirect Unity logs to a Logs folder in the project, and rotate them on every run, so no loga are ever lost. 6 | 7 | Alternatively, you can use it to figure out what a project is set to, if you can't remember (I know I can't). It will ask for confirmation before actually running Unity, and show you the command line it will use to do it, so you can doublecheck things. 8 | 9 | I run this on a git bash shell on Windows, and on Terminal (well, iTerm) on macOS. If you get weird errors on mac, make sure the script's line endings are set to LF (Linux), bash no like CRLF outside of Windows. 10 | 11 | ### Usage 12 | 13 | Make sure the script is set to executable (`chmod +x open-unity.sh`) if you want to run it with `./open-unity.sh`, or run it with `sh open-unity.sh` otherwise. 14 | 15 | `open-unity.sh [Options] [Build Target] [Batch mode flags] [other flags passed to Unity directly]` 16 | 17 | #### Example 18 | 19 | `./open-unity.sh -p [Path to Unity Project folder]` 20 | 21 | #### Options 22 | 23 | ``` 24 | -p|--path [value] Project path relative to the current directory (optional, current directory by default) 25 | -v|--version [value] Unity version (optional, autodetected by default from project settings) 26 | -u [value] Path to directory where Unity versions are installed (default: autodetected from Unity hub settings) 27 | --unity Path to Unity executable (if it really can't find your Unity installation) 28 | ``` 29 | 30 | #### Currently supported build targets 31 | 32 | ``` 33 | -w|--windows Set build target to Win64 34 | -m|--mac Set build target to Mac 35 | -a|--android Set build target to Android 36 | -i|--ios Set build target to iOS 37 | -x|--xbox Set build target to xbox 38 | -s|--ps4 Set build target to ps4 39 | -5|--ps5 Set build target to ps5 40 | -n|--switch Set build target to Switch 41 | -g|--webgl Set build target to WebGL 42 | ``` 43 | 44 | #### Batch mode flags 45 | 46 | ``` 47 | -q|--quit Run Unity with -quit flag 48 | -b|--batch Runs Unity in -batchmode mode. The default method name is BuildHelp.BuildIt_[TARGET]_[CONFIGURATION]. 49 | Use -e to set the method name, or -d/-r/-c to use the default name with a specific configuration. 50 | Implies -q 51 | 52 | -d|--debug Used with -b, sets the method to BuildHelp.BuildIt_[TARGET]_Dev 53 | -r|--release Used with -b, sets the method to BuildHelp.BuildIt_[TARGET]_Release 54 | -c|--configuration [value] Used with -b, sets the method to BuildHelp.BuildIt_[TARGET]_[CONFIGURATION], where CONFIGURATION is what you set here. 55 | -e|--method [value] Run Unity by invoking a method and exiting. Implies -q. 56 | ```` 57 | 58 | #### Cache server 59 | 60 | ``` 61 | -z|--cache [value] IP or hostname of unity accelerator 62 | --v1 Use cache server v1 63 | --v2 Use cache server v2 (accelerator) 64 | --nocache Don't add any cache server parameters 65 | ``` 66 | -------------------------------------------------------------------------------- /open-unity.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | # ------------------------------------------------------------ 4 | # Copyright (c) 2020, 2021, 2022 Andreia Gaita 5 | # Licensed under the MIT License. 6 | # ------------------------------------------------------------ 7 | 8 | { set +x; } 2>/dev/null 9 | SOURCE=$0 10 | DIR="$( pwd )" 11 | 12 | # unity version, pass -n|--unity to set 13 | UNITYVERSION="" 14 | # default cache server, pass --cache to set 15 | CACHESERVER="cachepi" 16 | #default cache server version (2 is accelerator) 17 | CACHEVERSION=2 18 | # folder where you stuff all your Unitys, pass in -u to set 19 | BASEUNITYPATH="/Applications/Unity/Hub/Editor" 20 | 21 | ISMAC=1 22 | ISWIN= 23 | HUBPATH="" 24 | OS="Mac" 25 | BIN="" 26 | UNITYTOOLSPATH="" 27 | CONFIGURATION=Dev 28 | 29 | BUILD=0 30 | BATCH=0 31 | QUIT=0 32 | LICENSE= 33 | LICRETURN=0 34 | LISTVERSIONS=0 35 | SWITCHVERSION=0 36 | PRINT=0 37 | SKIPPATHCHECK=0 38 | AUTOCONFIRM=0 39 | FOREGROUND=0 40 | 41 | PROJECTPATH= 42 | TARGET="" 43 | METHOD="" 44 | ARGS=() 45 | UNITY_ARGS=() 46 | UNITYPATH="" 47 | 48 | if [[ -e "/c/" ]]; then 49 | OS="Windows" 50 | ISMAC= 51 | ISWIN=1 52 | fi 53 | 54 | if [[ "$OS" == "Windows" ]]; then 55 | BIN="/usr/bin/" 56 | fi 57 | 58 | RM="${BIN}rm" 59 | CAT="${BIN}cat" 60 | GREP="${BIN}grep" 61 | CUT="${BIN}cut" 62 | DATE="${BIN}date" 63 | CP="${BIN}cp" 64 | BIN2TXT="binary2text" 65 | SED="sed" 66 | MKDIR="mkdir -p" 67 | LS="ls -y" 68 | if [[ "$($LS -y>/dev/null 2>&1 && echo 0 || echo 1)" == "1" ]];then 69 | LS="ls" 70 | fi 71 | 72 | if [[ -z ${TMPDIR:-} ]]; then 73 | TMPDIR=/tmp 74 | fi 75 | 76 | if [[ "$OS" == "Windows" ]]; then 77 | BASEUNITYPATH="/c/Program Files/Unity/Hub/Editor" 78 | BIN2TXT="${BIN2TXT}.exe" 79 | fi 80 | 81 | 82 | function usage_platforms() { 83 | cat << EOF 84 | 85 | Build Targets (optional, autodetected from current project settings): 86 | -w|--windows Set build target to Win64 87 | -m|--mac Set build target to Mac 88 | -l|--linux Set build target to Linux 89 | -a|--android Set build target to Android 90 | -i|--ios Set build target to iOS 91 | -x|--xbox Set build target to Xbox One 92 | -s|--ps4 Set build target to ps4 93 | -5|--ps5 Set build target to ps5 94 | -n|--switch Set build target to Switch 95 | -g|--webgl Set build target to WebGL 96 | -xx|--xbox1gdk Set build target to GameCore Xbox One 97 | -xs|--xboxs Set build target to GameCore Xbox Series S/X 98 | --tvos Set build target to tvOS 99 | --stadia Set build target to Stadia 100 | EOF 101 | } 102 | 103 | function usage() { 104 | cat << EOF 105 | 106 | Usage: 107 | 108 | open.sh [Options] [Build Target] [Batch mode flags] [other flags passed to Unity directly] 109 | 110 | Example: 111 | ./open.sh -p [Path to Unity Project folder] 112 | 113 | By default it will detect what build target and Unity version the project is currently set to and use that. 114 | 115 | Use -h for a list of all the options. 116 | Use --trace to enable bash trace mode (see everything as it is executed) 117 | 118 | -ov|--open-version List all available Unity versions for selection and open the project with the selected version 119 | -u [value] Path to directory where Unity versions are installed (default: $BASEUNITYPATH) 120 | EOF 121 | } 122 | 123 | function help() { 124 | usage 125 | 126 | usage_platforms 127 | 128 | cat << EOF 129 | 130 | General Options: 131 | -p|--path [value] Project path relative to the current directory (optional, current directory by default) 132 | -v|--version [value] Unity version (optional, autodetected by default from project settings) 133 | 134 | -lv|--list-versions List all available Unity versions 135 | -ov|--open-version List all available Unity versions for selection and open the project with the selected version 136 | 137 | -u [value] Path to directory where Unity versions are installed (default: $BASEUNITYPATH) 138 | 139 | --unity Path to Unity.exe/Unity.app executable 140 | 141 | --print Print the current version of Unity and the current build target that the project is set to. 142 | 143 | --no-project Run unity without passing in a project path, it uses a temporary path instead. 144 | This is especially useful for switching licenses, where you don't want Unity 145 | to spend time importing a project. 146 | Unity will complain that the path doesn't contain a project, but the license 147 | update runs before that, so you can ignore the errors. 148 | 149 | -y|--auto-confirm Don't ask for confirmation before running Unity 150 | -f|--foreground Run Unity in the foreground (off by default) 151 | 152 | Batch mode: 153 | -q|--quit Run Unity with -quit flag 154 | --no-quit Don't send the -q argument to Unity, even if other flags imply it. 155 | 156 | -b|--batch Runs Unity in -batchmode mode. The default method name is BuildHelp.BuildIt_[TARGET]_[CONFIGURATION] 157 | Use -e to set the method name, or -d/-r/-c to use the default name with a specific configuration. 158 | Implies -q 159 | 160 | -e|--method [value] Run Unity by invoking a method and exiting. Implies -q. 161 | -d|--debug Used with -b, sets the method to BuildHelp.BuildIt_[TARGET]_Dev 162 | -r|--release Used with -b, sets the method to BuildHelp.BuildIt_[TARGET]_Release 163 | -c|--configuration [value] Used with -b, sets the method to BuildHelp.BuildIt_[TARGET]_[CONFIGURATION], 164 | where CONFIGURATION is what you set here. 165 | 166 | Cache server: 167 | -z|--cache [value] IP or hostname of unity accelerator 168 | -k|--nocache Don't add any cache server parameters 169 | --v1 Use cache server v1 170 | --v2 Use cache server v2 (accelerator) 171 | 172 | License management: 173 | -lic|--license Select license to use, returning the current one first. 174 | Run this with --no-project for switching licenses without opening a project. 175 | 176 | -llist|--license-list List configured licenses 177 | -lset|--license-set Configure a license 178 | -lrem|--license-remove Remove a configured license 179 | -lret|--license-return Return the current license 180 | EOF 181 | } 182 | 183 | 184 | function main() { 185 | 186 | if [[ "$OS" == "Windows" ]]; then 187 | HUBPATH="$( echo ~/AppData/Roaming/UnityHub/ | xargs realpath )" || true 188 | else 189 | HUBPATH="$( cd ~/Library/Application\ Support/UnityHub/ && pwd )" || true 190 | fi 191 | 192 | if [[ -d $HUBPATH ]]; then 193 | HUBPATH="$HUBPATH/secondaryInstallPath.json" 194 | fi 195 | 196 | if [[ -f $HUBPATH ]]; then 197 | tmp="$( $CAT "$HUBPATH" | $SED -E 's, ,\\ ,g' | $SED -E 's,",,g' )" 198 | if [[ x"$tmp" != x"" ]]; then 199 | BASEUNITYPATH="$tmp" 200 | if [[ "$OS" == "Windows" ]]; then 201 | BASEUNITYPATH="$( realpath "$BASEUNITYPATH" )" 202 | fi 203 | fi 204 | fi 205 | 206 | local ARGSONLY=0 207 | while (( "$#" )); do 208 | if [[ "$ARGSONLY" == "1" ]]; then 209 | ARGS+=("$1") 210 | shift 211 | continue 212 | fi 213 | 214 | case "$1" in 215 | -d|--debug) 216 | CONFIGURATION="Dev" 217 | ;; 218 | -r|--release) 219 | CONFIGURATION="Release" 220 | ;; 221 | -b|--batch) 222 | BATCH=1 223 | QUIT=1 224 | ;; 225 | -b|--build) 226 | BUILD=1 227 | BATCH=1 228 | QUIT=1 229 | ;; 230 | -c) 231 | shift 232 | CONFIGURATION=$1 233 | ;; 234 | -v|--version) 235 | shift 236 | UNITYVERSION="$1" 237 | ;; 238 | -p|--path) 239 | shift 240 | PROJECTPATH="${DIR}/${1}" 241 | ;; 242 | -e|--method) 243 | shift 244 | METHOD=$1 245 | QUIT=1 246 | ;; 247 | -z|--cache) 248 | shift 249 | CACHESERVER="$1" 250 | CUSTOM_CACHESERVER=1 251 | ;; 252 | -u) 253 | shift 254 | BASEUNITYPATH="$1" 255 | ;; 256 | --unity) 257 | shift 258 | UNITYPATH="$1" 259 | ;; 260 | -q|--quit) 261 | QUIT=1 262 | ;; 263 | --noquit) 264 | QUIT=0 265 | ;; 266 | --v1) 267 | CACHEVERSION=1 268 | ;; 269 | --v2) 270 | CACHEVERSION=2 271 | ;; 272 | -k|--nocache) 273 | CACHEVERSION=0 274 | ;; 275 | -lv|--list-versions) 276 | LISTVERSIONS=1 277 | ;; 278 | -ov|--open-version) 279 | SWITCHVERSION=1 280 | ;; 281 | --print) 282 | PRINT=1 283 | ;; 284 | -lic|--license) 285 | LICENSE=0 286 | LICRETURN=1 287 | if [[ ${2:-0} == [1-9] ]]; then 288 | LICENSE=$2 289 | shift 290 | fi 291 | ;; 292 | -lset|--license-set) 293 | shift 294 | license_set $@ 295 | exit 0 296 | ;; 297 | -llist|--license-list) 298 | shift 299 | license_list $@ 300 | exit 0 301 | ;; 302 | -lrem|--license-remove) 303 | shift 304 | license_remove $@ 305 | exit 0 306 | ;; 307 | -lret|--license-return) 308 | LICENSE= 309 | LICRETURN=1 310 | if [[ ${2:-0} == [1-9] ]]; then 311 | LICENSE=$2 312 | shift 313 | fi 314 | ;; 315 | --no-project) 316 | PROJECTPATH=$TMPDIR 317 | SKIPPATHCHECK=1 318 | ;; 319 | -y|--auto-confirm) 320 | AUTOCONFIRM=1 321 | ;; 322 | -f|--foreground) 323 | FOREGROUND=1 324 | ;; 325 | -h|--help) 326 | help 327 | exit 0 328 | ;; 329 | --args) 330 | ARGSONLY=1 331 | ;; 332 | --trace) 333 | { set -x; } 2>/dev/null 334 | ;; 335 | *) 336 | # check if it's a platform flag, otherwise append it to the arguments 337 | local tmp=$(platforms "$1") 338 | if [[ -n $tmp ]]; then 339 | TARGET=$tmp 340 | elif [[ -d "$1" && "$PROJECTPATH" == "" ]]; then 341 | PROJECTPATH=$(cd "$1" && pwd) 342 | else 343 | ARGS+=("$1") 344 | fi 345 | ;; 346 | esac 347 | shift 348 | done 349 | 350 | if [[ "${LISTVERSIONS}" == "1" ]]; then 351 | unityversions 352 | exit 0 353 | fi 354 | 355 | if [[ -f ~/.spoiledcat/defaults.yaml ]]; then 356 | eval $(parse_yaml ~/.spoiledcat/defaults.yaml "OU_") 357 | if [[ x"${CUSTOM_CACHESERVER:-}" != x"1" && x"$CACHEVERSION" != x"0" && -n ${OU_cacheserver_name:-} ]]; then 358 | CACHESERVER=${OU_cacheserver_name} 359 | fi 360 | fi 361 | 362 | if [[ "$PROJECTPATH" == "" ]]; then 363 | PROJECTPATH="$DIR" 364 | fi 365 | 366 | PROJECTPATH="$(echo "$PROJECTPATH" | $SED -E 's,/$,,')" 367 | 368 | LOGFOLDER="$PROJECTPATH/Logs" 369 | LOGFILE="$LOGFOLDER/Editor.log" 370 | 371 | if [[ ! -d "${PROJECTPATH}/Assets" && $SKIPPATHCHECK != 1 ]]; then 372 | echo "" >&2 373 | echo "Error: Invalid path ${PROJECTPATH}" >&2 374 | echo "Would you like to create a new project in ${PROJECTPATH}?" 375 | read -n1 -r -p "Press y to create a new project in ${PROJECTPATH}, or any key to cancel..." key 376 | if [[ "$key" == 'y' ]]; then 377 | $MKDIR "${PROJECTPATH}/Assets" 378 | else 379 | usage 380 | exit 1 381 | fi 382 | fi 383 | 384 | if [[ "${SWITCHVERSION}" == "1" ]]; then 385 | unityversions 386 | local available=$($LS "$BASEUNITYPATH"|grep -v Hub) 387 | available=(${available}) 388 | 389 | echo "Select a version, or enter to cancel" 390 | local selection= 391 | read -r selection 392 | if [[ x"${selection:-}"x =~ ^x[1-9]{1}[0-9]*x$ ]]; then 393 | selection=$((selection-1)) 394 | UNITYVERSION=${available[selection]} 395 | else 396 | echo "Set which Unity to use with -v" >&2 397 | usage 398 | exit 2 399 | fi 400 | fi 401 | 402 | # print data about the project and exit 403 | if [[ "${PRINT}" == "1" ]]; then 404 | if [[ -f "$PROJECTPATH/ProjectSettings/ProjectVersion.txt" ]]; then 405 | UNITYVERSION="$( $CAT "$PROJECTPATH/ProjectSettings/ProjectVersion.txt" | $GREP "m_EditorVersion:" | $CUT -d' ' -f 2)" 406 | fi 407 | 408 | local _latestunity=$($LS "$BASEUNITYPATH"|grep -v Hub|tail -n1) 409 | UNITYPATH="${BASEUNITYPATH}/${_latestunity}" 410 | if [[ "$OS" == "Mac" ]]; then 411 | UNITYTOOLSPATH="$UNITYPATH/Unity.app/Contents/Tools" 412 | UNITYPATH="$UNITYPATH/Unity.app/Contents/MacOS" 413 | else 414 | UNITYTOOLSPATH="$UNITYPATH/Editor/Data/Tools" 415 | UNITYPATH="$UNITYPATH/Editor" 416 | fi 417 | 418 | EDITORUSERBUILDSETTINGS="$PROJECTPATH/Library/EditorUserBuildSettings.asset" 419 | BUILDSETTINGS="$DIR/buildsettings.txt" 420 | $RM -f "$BUILDSETTINGS" || true 421 | TARGET="Not Set" 422 | 423 | if [[ -e "$EDITORUSERBUILDSETTINGS" ]]; then 424 | 425 | "$UNITYTOOLSPATH/$BIN2TXT" "$EDITORUSERBUILDSETTINGS" "$BUILDSETTINGS" || true 426 | 427 | if [[ -e "$BUILDSETTINGS" ]]; then 428 | 429 | ACTIVETARGET="$( $CAT "$BUILDSETTINGS" | $GREP "m_ActiveBuildTarget " | CUT -d' ' -f 2)" 430 | $RM -f "$BUILDSETTINGS" || true 431 | 432 | TARGET=$(platforms "$ACTIVETARGET") 433 | 434 | if [[ "$TARGET" == "" ]]; then 435 | TARGET=Unknown 436 | fi 437 | fi 438 | fi 439 | 440 | cat << EOF 441 | 442 | Project: ${PROJECTPATH} 443 | Unity version: ${UNITYVERSION} 444 | Build Target: ${TARGET} 445 | EOF 446 | 447 | exit 0 448 | fi 449 | 450 | 451 | if [[ "${UNITYPATH}" == "" ]]; then 452 | if [[ "${UNITYVERSION}" == "" ]]; then 453 | if [[ -f "$PROJECTPATH/ProjectSettings/ProjectVersion.txt" ]]; then 454 | UNITYVERSION="$( $CAT "$PROJECTPATH/ProjectSettings/ProjectVersion.txt" | $GREP "m_EditorVersion:" | $CUT -d' ' -f 2)" 455 | else 456 | echo "" >&2 457 | echo "Error: No Unity version detected in project." >&2 458 | unityversions 459 | local available=$($LS "$BASEUNITYPATH"|grep -v Hub) 460 | available=(${available}) 461 | 462 | echo "Select a version, or enter to cancel" 463 | local selection= 464 | read -r selection 465 | if [[ x"${selection:-}"x =~ ^x[1-9]{1}[0-9]*x$ ]]; then 466 | selection=$((selection-1)) 467 | UNITYVERSION=${available[selection]} 468 | else 469 | echo "Set which Unity to use -v" >&2 470 | usage 471 | exit 2 472 | fi 473 | fi 474 | else 475 | if [[ ! -d "${BASEUNITYPATH}/${UNITYVERSION}" && -d "${BASEUNITYPATH}/${UNITYVERSION}f1" ]]; then 476 | UNITYVERSION="${UNITYVERSION}f1" 477 | fi 478 | if [[ ! -d "${BASEUNITYPATH}/${UNITYVERSION}" && -d "${BASEUNITYPATH}/${UNITYVERSION}f2" ]]; then 479 | UNITYVERSION="${UNITYVERSION}f2" 480 | fi 481 | if [[ ! -d "${BASEUNITYPATH}/${UNITYVERSION}" && -d "${BASEUNITYPATH}/${UNITYVERSION}f3" ]]; then 482 | UNITYVERSION="${UNITYVERSION}f3" 483 | fi 484 | if [[ ! -d "${BASEUNITYPATH}/${UNITYVERSION}" && -d "${BASEUNITYPATH}/${UNITYVERSION}f4" ]]; then 485 | UNITYVERSION="${UNITYVERSION}f4" 486 | fi 487 | fi 488 | 489 | if [[ -d "${BASEUNITYPATH}/${UNITYVERSION}" ]]; then 490 | echo "Using Unity v$UNITYVERSION" 491 | UNITYPATH="${BASEUNITYPATH}/${UNITYVERSION}" 492 | else 493 | echo "" >&2 494 | echo "Error: Unity not found at ${BASEUNITYPATH}/${UNITYVERSION}" >&2 495 | echo "Install Unity v$UNITYVERSION or use a different version with -ov or -v" >&2 496 | usage 497 | exit 2 498 | fi 499 | 500 | 501 | if [[ "$OS" == "Mac" ]]; then 502 | UNITYTOOLSPATH="$UNITYPATH/Unity.app/Contents/Tools" 503 | UNITYPATH="$UNITYPATH/Unity.app/Contents/MacOS" 504 | else 505 | UNITYTOOLSPATH="$UNITYPATH/Editor/Data/Tools" 506 | UNITYPATH="$UNITYPATH/Editor" 507 | fi 508 | else 509 | UNITYTOOLSPATH="$UNITYPATH/Data/Tools" 510 | fi 511 | 512 | if [[ ! -d "${UNITYPATH}" ]]; then 513 | echo "" >&2 514 | echo "Error: Unity not found at ${UNITYPATH}" >&2 515 | usage 516 | exit 1 517 | fi 518 | 519 | if [[ ! -f "$UNITYTOOLSPATH/$BIN2TXT" ]]; then 520 | echo "Error: Unity not found at ${UNITYPATH}" >&2 521 | exit 1 522 | fi 523 | 524 | if [[ "$TARGET" == "" ]]; then 525 | 526 | EDITORUSERBUILDSETTINGS="$PROJECTPATH/Library/EditorUserBuildSettings.asset" 527 | BUILDSETTINGS="$DIR/buildsettings.txt" 528 | $RM -f "$BUILDSETTINGS" || true 529 | 530 | if [[ -e "$EDITORUSERBUILDSETTINGS" ]]; then 531 | 532 | "$UNITYTOOLSPATH/$BIN2TXT" "$EDITORUSERBUILDSETTINGS" "$BUILDSETTINGS" || true 533 | 534 | if [[ -e "$BUILDSETTINGS" ]]; then 535 | 536 | ACTIVETARGET="$( $CAT "$BUILDSETTINGS" | $GREP "m_ActiveBuildTarget " | CUT -d' ' -f 2)" 537 | $RM -f "$BUILDSETTINGS" || true 538 | 539 | TARGET=$(platforms "$ACTIVETARGET") 540 | 541 | if [[ "$TARGET" == "" ]]; then 542 | echo "Error: Invalid target $ACTIVETARGET" >&2 543 | usage 544 | usage_platforms 545 | exit 1 546 | fi 547 | fi 548 | fi 549 | fi 550 | 551 | if [[ "$TARGET" == "" ]]; then 552 | echo "" >&2 553 | local currentplat=-w 554 | [[ -n $ISMAC ]] && currentplat=-m 555 | TARGET=$(platforms "$currentplat") 556 | echo "Project has no active target, defaulting to ${TARGET}" >&2 557 | echo "Pass one of the platform flags to set a specific platform." >&2 558 | fi 559 | 560 | if [[ "$BUILD" == "1" && "$METHOD" == "" ]]; then 561 | METHOD="BuildHelp.BuildIt_${TARGET}_${CONFIGURATION}" 562 | fi 563 | 564 | UNITY_ARGS+=("-disable-assembly-updater") 565 | 566 | if [[ "$CACHEVERSION" == "1" ]]; then 567 | UNITY_ARGS+=("-CacheServerIPAddress" "$CACHESERVER") 568 | elif [[ "$CACHEVERSION" == "2" ]]; then 569 | UNITY_ARGS+=("-cacheServerEndpoint" "$CACHESERVER" "-adb2" "-EnableCacheServer") 570 | fi 571 | 572 | if [[ "$BATCH" == "1" ]]; then 573 | UNITY_ARGS+=("-batchmode" "-nographics") 574 | fi 575 | 576 | if [[ "$QUIT" == "1" ]]; then 577 | UNITY_ARGS+=("-quit") 578 | fi 579 | 580 | if [[ x"$METHOD" != x"" ]]; then 581 | UNITY_ARGS+=("-executeMethod" "${METHOD}") 582 | fi 583 | 584 | UNITY_ARGS+=("-logFile" "$LOGFILE") 585 | 586 | # do the license dance when the user has selected an existing configured license 587 | if [[ x"$LICENSE" != x"" || "$LICRETURN" == "1" ]]; then 588 | if [[ ! -f ~/.spoiledcat/licenses.yaml ]]; then 589 | echo "There are no configured license" 590 | return 0 591 | fi 592 | eval $(parse_yaml ~/.spoiledcat/licenses.yaml "UL_") 593 | if [[ -z ${UL_licenses_:-} ]]; then 594 | echo "There are no configured license" 595 | return 0 596 | fi 597 | 598 | local onlyreturn=0 599 | 600 | if [[ "$LICENSE" == "" ]]; then 601 | onlyreturn=1 602 | fi 603 | 604 | if [[ $LICENSE != [1-9] ]]; then 605 | 606 | local action="" 607 | if [[ $onlyreturn == 1 ]]; then 608 | action="return? If they all share the same credentials, pick any." 609 | else 610 | action="switch to?" 611 | fi 612 | 613 | echo "" 614 | echo "Which license to you want to ${action}" 615 | license_select 616 | fi 617 | 618 | license=($(license_get "$LICENSE")) 619 | 620 | UNITY_ARGS_LICENSE=("${UNITY_ARGS[@]}" "-batchmode" "-quit" "-projectPath" "$TMPDIR" "-nographics" "-username" "${license[0]}" "-password" "${license[1]}") 621 | 622 | if [[ "$LICRETURN" == "1" ]]; then 623 | echo "" 624 | echo "Returning license first..." 625 | echo "" 626 | 627 | run_unity 1 "${UNITY_ARGS_LICENSE[@]}" "-returnlicense" 628 | fi 629 | 630 | if [[ $onlyreturn == 1 ]]; then 631 | return 0 632 | else 633 | echo "" 634 | run_unity 1 "${UNITY_ARGS_LICENSE[@]}" "-serial" "${license[2]}" 635 | fi 636 | fi 637 | 638 | UNITY_ARGS+=("-buildTarget" "$TARGET" "-projectPath" "$PROJECTPATH" "${ARGS[@]}") 639 | 640 | echo "Opening project ${PROJECTPATH} with $UNITYVERSION : $TARGET" 641 | run_unity $FOREGROUND "${UNITY_ARGS[@]}" 642 | 643 | } 644 | 645 | function run_unity { 646 | local wait=$1 647 | shift 648 | 649 | local cmd=($"$UNITYPATH/Unity") 650 | while (( "$#" )); do 651 | cmd+=("$1") 652 | shift 653 | done 654 | 655 | echo "${cmd[@]}" 656 | 657 | if [[ $AUTOCONFIRM != 1 ]]; then 658 | read -n1 -r -p "Press space to continue..." key 659 | 660 | if [[ x"$key" != x'' ]]; then 661 | return 662 | fi 663 | fi 664 | 665 | SUBFILENAME=$( $DATE +%Y%m%d-%H%M%S ) 666 | 667 | if [[ -e "$LOGFILE" ]]; then 668 | $CP "$LOGFILE" "$LOGFOLDER/Editor_$SUBFILENAME.log" 669 | fi 670 | 671 | { set +e; } 2>/dev/null 672 | oldifs=$IFS 673 | # really make sure bash doesn't split words and add quotes when we're invoking this 674 | IFS=$ 675 | if [[ $wait == 1 ]]; then 676 | ${cmd[@]} 677 | else 678 | ${cmd[@]} & 679 | fi 680 | IFS=$oldifs 681 | { set -e; } 2>/dev/null 682 | 683 | echo "" 684 | return 0 685 | } 686 | 687 | # ======= HELPERS ========== # 688 | 689 | function unityversions() { 690 | local available=$($LS "$BASEUNITYPATH"|grep -v Hub) 691 | local availablecount=(${available#}) 692 | availablecount=${#availablecount[@]} 693 | available=(${available}) 694 | availablecount=$((availablecount-1)) 695 | for i in $(seq 0 $availablecount); do 696 | echo "$((i+1))) ${available[$i]}" 697 | done 698 | } 699 | 700 | function platforms() { 701 | case $1 in 702 | 2|-m|--mac) echo 'Mac';; 703 | 5|--win32) echo 'Win32';; 704 | 9|-i|--ios) echo 'iOS';; 705 | 13|-a|--android) echo 'Android';; 706 | 19|-w|--windows) echo 'Win64';; 707 | 20|-g|--webgl) echo 'WebGL';; 708 | 24|-l|--linux) echo 'Linux64';; 709 | 31|-s|--ps4) echo 'PS4';; 710 | 33|-x|--xbox) echo 'XboxOne';; 711 | 37|--tvos) echo 'tvOS';; 712 | 38|-n|--switch) echo 'Switch';; 713 | 40|--stadia) echo 'Stadia';; 714 | 42|-xs|--scarlett|--xboxs) echo 'GameCoreScarlett';; 715 | 43|-xx|--xbox1gdk) echo 'GameCoreXboxOne';; 716 | 44|-5|--ps5) echo 'PS5';; 717 | *) echo '';; 718 | esac 719 | } 720 | 721 | LIC_PLAT=("" General Switch PS4 PS5 "Xbox One" "Xbox S/X") 722 | 723 | function license_select { 724 | licensecount=(${UL_licenses_#}) 725 | licensecount=${#licensecount[@]} 726 | 727 | for i in $(seq 1 "$licensecount"); do 728 | local plat="UL_licenses_${i}_platform" 729 | local license="UL_licenses_${i}_license" 730 | echo "$i) ${!plat} => ${!license}" 731 | done 732 | 733 | local selection= 734 | read -r selection 735 | if [[ ${selection:-} == [1-9] ]]; then 736 | LICENSE=$selection 737 | fi 738 | } 739 | 740 | function license_get { 741 | local platform="UL_licenses_${1}_platform" 742 | local license="UL_licenses_${1}_license" 743 | local username="UL_licenses_${1}_username" 744 | local password="UL_licenses_${1}_password" 745 | printf '%q %q %q' "${!username}" "${!password}" "${!license}" 746 | } 747 | 748 | 749 | function license_set { 750 | 751 | cat << EOF 752 | This will store a license key so you can switch licenses with the --license option, for the given platform. 753 | Note: Unity requires passing the username, password and license key on the command line as plain text arguments in order to switch licenses. 754 | The values set here are stored in plaintext in ~/.spoiledcat/licenses.yaml 755 | EOF 756 | 757 | local continue 758 | echo "" 759 | read -n1 -r -p 'Continue? (Enter or Space to continue, or any other key to quit):' continue 760 | 761 | if [[ -n "$continue" ]]; then 762 | echo "" 763 | echo "Exiting" 764 | return 765 | fi 766 | 767 | 768 | local platform 769 | local user 770 | local pwd 771 | local license 772 | 773 | cat << EOF 774 | 775 | Platform for this key: 776 | EOF 777 | 778 | local count=${#LIC_PLAT[@]} 779 | count=$((count-1)) 780 | for i in $(seq 1 $count); do 781 | cat << EOF 782 | $i) ${LIC_PLAT[$i]} 783 | EOF 784 | done 785 | 786 | local selection= 787 | read -r -p "Which selection? " selection 788 | 789 | if [[ ${selection:-} != [1-9] ]]; then 790 | echo "" 791 | echo "Exiting" 792 | return 793 | fi 794 | 795 | if [[ -z ${LIC_PLAT[$selection]:-} ]] ; then 796 | echo "" 797 | echo "Exiting" 798 | return 799 | fi 800 | 801 | local platform=${LIC_PLAT[$selection]} 802 | { set -u; } 2>/dev/null 803 | 804 | echo "" 805 | echo "Platform selected: $platform" 806 | 807 | echo "" 808 | read -r -p "Unity username: " username 809 | read -r -s -p "Unity password: " password 810 | echo "" 811 | read -r -p "Unity license key: " license 812 | echo "" 813 | 814 | $MKDIR ~/.spoiledcat 815 | if [[ -f ~/.spoiledcat/licenses.yaml ]]; then 816 | eval $(parse_yaml ~/.spoiledcat/licenses.yaml "UL_") 817 | 818 | if [[ -z ${UL_licenses_:-} ]]; then 819 | local entry=$(format_license_entry "$platform" "$username" "$password" "$license") 820 | cat > ~/.spoiledcat/licenses.yaml << EOF 821 | licenses: 822 | ${entry} 823 | EOF 824 | else 825 | lic_add_or_update "$platform" "$username" "$password" "$license" 826 | fi 827 | else 828 | local entry=$(format_license_entry "$platform" "$username" "$password" "$license") 829 | cat > ~/.spoiledcat/licenses.yaml << EOF 830 | licenses: 831 | ${entry} 832 | EOF 833 | fi 834 | } 835 | 836 | function license_list() { 837 | if [[ ! -f ~/.spoiledcat/licenses.yaml ]]; then 838 | echo "There are no configured license" 839 | return 0 840 | fi 841 | 842 | eval $(parse_yaml ~/.spoiledcat/licenses.yaml "UL_") 843 | 844 | if [[ -z ${UL_licenses_:-} ]]; then 845 | echo "There are no configured license" 846 | return 0 847 | fi 848 | 849 | licensecount=(${UL_licenses_#}) 850 | licensecount=${#licensecount[@]} 851 | for i in $(seq 1 "$licensecount"); do 852 | local platform="UL_licenses_${i}_platform" 853 | local license="UL_licenses_${i}_license" 854 | echo "${!platform} => ${!license}" 855 | done 856 | } 857 | 858 | function license_remove() { 859 | if [[ ! -f ~/.spoiledcat/licenses.yaml ]]; then 860 | echo "There are no configured license" 861 | return 0 862 | fi 863 | eval $(parse_yaml ~/.spoiledcat/licenses.yaml "UL_") 864 | if [[ -z ${UL_licenses_:-} ]]; then 865 | echo "There are no configured license" 866 | return 0 867 | fi 868 | 869 | cat < ${!license}" 879 | done 880 | 881 | local selection= 882 | read -r selection 883 | 884 | if [[ ${selection:-} == [1-9] ]]; then 885 | lic_remove "$selection" 886 | fi 887 | } 888 | 889 | function lic_remove() { 890 | local index=$1 891 | shift 892 | 893 | local yaml="" 894 | 895 | local licensecount=(${UL_licenses_#}) 896 | licensecount=${#licensecount[@]} 897 | for i in $(seq 1 "$licensecount"); do 898 | local platform="UL_licenses_${i}_platform" 899 | platform=${!platform} 900 | if [[ $i == $index ]]; then 901 | echo "Removing $platform" 902 | continue 903 | fi 904 | local username="UL_licenses_${i}_username" 905 | username=${!username} 906 | local password="UL_licenses_${i}_password" 907 | password=${!password} 908 | local license="UL_licenses_${i}_license" 909 | license=${!license} 910 | 911 | local entry=$(format_license_entry "$platform" "$username" "$password" "$license") 912 | yaml=$(cat < ~/.spoiledcat/licenses.yaml << EOF 920 | licenses: 921 | ${yaml} 922 | EOF 923 | 924 | } 925 | 926 | function lic_add_or_update() { 927 | local newplat=$1 928 | shift 929 | local newuser=$1 930 | shift 931 | local newpwd=$1 932 | shift 933 | local newkey=$1 934 | shift 935 | 936 | local yaml="" 937 | local found= 938 | 939 | local licensecount=(${UL_licenses_#}) 940 | licensecount=${#licensecount[@]} 941 | for i in $(seq 1 "$licensecount"); do 942 | local platform="UL_licenses_${i}_platform" 943 | platform=${!platform} 944 | local username="UL_licenses_${i}_username" 945 | username=${!username} 946 | local password="UL_licenses_${i}_password" 947 | password=${!password} 948 | local license="UL_licenses_${i}_license" 949 | license=${!license} 950 | 951 | if [[ "$platform" == "$newplat" ]]; then 952 | found=1 953 | username=$newuser 954 | password=$newpwd 955 | license=$newkey 956 | fi 957 | local entry=$(format_license_entry "$platform" "$username" "$password" "$license") 958 | yaml=$(cat < ~/.spoiledcat/licenses.yaml << EOF 975 | licenses: 976 | ${yaml} 977 | EOF 978 | 979 | } 980 | 981 | function format_license_entry() { 982 | local platform=$1 983 | shift 984 | local username=$1 985 | shift 986 | local password=$1 987 | shift 988 | local license=$1 989 | shift 990 | cat <&1 | grep -q "GNU Awk" ; then 1008 | # GNU Awk detected 1009 | indexfix=-1 1010 | fi 1011 | 1012 | local s='[[:space:]]*' sm='[ \t]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034') i=' ' 1013 | cat "$1" | \ 1014 | awk -F"$fs" "{multi=0; 1015 | if(match(\$0,/$sm\|$sm$/)){multi=1; sub(/$sm\|$sm$/,\"\");} 1016 | if(match(\$0,/$sm>$sm$/)){multi=2; sub(/$sm>$sm$/,\"\");} 1017 | while(multi>0){ 1018 | str=\$0; gsub(/^$sm/,\"\", str); 1019 | indent=index(\$0,str); 1020 | indentstr=substr(\$0, 0, indent+$indexfix) \"$i\"; 1021 | obuf=\$0; 1022 | getline; 1023 | while(index(\$0,indentstr)){ 1024 | obuf=obuf substr(\$0, length(indentstr)+1); 1025 | if (multi==1){obuf=obuf \"\\\\n\";} 1026 | if (multi==2){ 1027 | if(match(\$0,/^$sm$/)) 1028 | obuf=obuf \"\\\\n\"; 1029 | else obuf=obuf \" \"; 1030 | } 1031 | getline; 1032 | } 1033 | sub(/$sm$/,\"\",obuf); 1034 | print obuf; 1035 | multi=0; 1036 | if(match(\$0,/$sm\|$sm$/)){multi=1; sub(/$sm\|$sm$/,\"\");} 1037 | if(match(\$0,/$sm>$sm$/)){multi=2; sub(/$sm>$sm$/,\"\");} 1038 | } 1039 | print}" | \ 1040 | sed -e "s|^\($s\)?|\1-|" \ 1041 | -ne "s|^$s#.*||;s|$s#[^\"']*$||;s|^\([^\"'#]*\)#.*|\1|;t1;t;:1;s|^$s\$||;t2;p;:2;d" | \ 1042 | sed -ne "s|,$s\]$s\$|]|" \ 1043 | -e ":1;s|^\($s\)\($w\)$s:$s\(&$w\)\?$s\[$s\(.*\)$s,$s\(.*\)$s\]|\1\2: \3[\4]\n\1$i- \5|;t1" \ 1044 | -e "s|^\($s\)\($w\)$s:$s\(&$w\)\?$s\[$s\(.*\)$s\]|\1\2: \3\n\1$i- \4|;" \ 1045 | -e ":2;s|^\($s\)-$s\[$s\(.*\)$s,$s\(.*\)$s\]|\1- [\2]\n\1$i- \3|;t2" \ 1046 | -e "s|^\($s\)-$s\[$s\(.*\)$s\]|\1-\n\1$i- \2|;p" | \ 1047 | sed -ne "s|,$s}$s\$|}|" \ 1048 | -e ":1;s|^\($s\)-$s{$s\(.*\)$s,$s\($w\)$s:$s\(.*\)$s}|\1- {\2}\n\1$i\3: \4|;t1" \ 1049 | -e "s|^\($s\)-$s{$s\(.*\)$s}|\1-\n\1$i\2|;" \ 1050 | -e ":2;s|^\($s\)\($w\)$s:$s\(&$w\)\?$s{$s\(.*\)$s,$s\($w\)$s:$s\(.*\)$s}|\1\2: \3 {\4}\n\1$i\5: \6|;t2" \ 1051 | -e "s|^\($s\)\($w\)$s:$s\(&$w\)\?$s{$s\(.*\)$s}|\1\2: \3\n\1$i\4|;p" | \ 1052 | sed -e "s|^\($s\)\($w\)$s:$s\(&$w\)\(.*\)|\1\2:\4\n\3|" \ 1053 | -e "s|^\($s\)-$s\(&$w\)\(.*\)|\1- \3\n\2|" | \ 1054 | sed -ne "s|^\($s\):|\1|" \ 1055 | -e "s|^\($s\)\(---\)\($s\)||" \ 1056 | -e "s|^\($s\)\(\.\.\.\)\($s\)||" \ 1057 | -e "s|^\($s\)-$s[\"']\(.*\)[\"']$s\$|\1$fs$fs\2|p;t" \ 1058 | -e "s|^\($s\)\($w\)$s:$s[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p;t" \ 1059 | -e "s|^\($s\)-$s\(.*\)$s\$|\1$fs$fs\2|" \ 1060 | -e "s|^\($s\)-\?\($w-\?$w\?\)$s:$s[\"']\?\(.*\)$s\$|\1$fs\2$fs\3|" \ 1061 | -e "s|^\($s\)[\"']\?\([^&][^$fs]\+\)[\"']$s\$|\1$fs$fs$fs\2|" \ 1062 | -e "s|^\($s\)[\"']\?\([^&][^$fs]\+\)$s\$|\1$fs$fs$fs\2|" \ 1063 | -e "s|$s\$||p" | \ 1064 | awk -F"$fs" "{ 1065 | gsub(/\t/,\" \",\$1); 1066 | if(NF>3){if(value!=\"\"){value = value \" \";}value = value \$4;} 1067 | else { 1068 | if(match(\$1,/^&/)){anchor[substr(\$1,2)]=full_vn;getline}; 1069 | indent = length(\$1)/length(\"$i\"); 1070 | vname[indent] = \$2; 1071 | value= \$3; 1072 | for (i in vname) {if (i > indent) {delete vname[i]; idx[i]=0}} 1073 | if(length(\$2)== 0){ vname[indent]= ++idx[indent] }; 1074 | vn=\"\"; for (i=0; i0)&&index(val, ref)==1){ 1090 | tmpval=assignment[val]; 1091 | sub(ref,full_vn,val); 1092 | if(match(val,\"$separator\$\")){ 1093 | gsub(ref,full_vn,tmpval); 1094 | } else if (length(tmpval) > 0) { 1095 | #printf(\"%s=\\\"%s\\\"\n\", val, tmpval); 1096 | data[val]=tmpval; 1097 | } 1098 | assignment[val]=tmpval; 1099 | } 1100 | } 1101 | } 1102 | } else if (length(value) > 0) { 1103 | if (match(value,/:/)){ 1104 | sep=\":\"; 1105 | vn=substr(value,0,index(value,sep)-1); 1106 | value=substr(value,index(value,sep)+1); 1107 | gsub(/^[ \t\r\n]+/, \"\",value); 1108 | base_vn=full_vn; 1109 | full_vn=full_vn \"$separator\" vn; 1110 | base_vn=base_vn \"$separator\"; 1111 | #printf(\"%s=\\\"%s\\\"\n\", full_vn, value); 1112 | data[full_vn]=value; 1113 | #if(!match(assignment[base_vn], full_vn))assignment[base_vn]=assignment[base_vn] \" \" full_vn; 1114 | } else { 1115 | #printf(\"%s=\\\"%s\\\"\n\", full_vn, value); 1116 | data[full_vn]=value; 1117 | } 1118 | } 1119 | }END{ 1120 | for(val in data){ 1121 | printf(\"%s=\\\"%s\\\"\n\", val, data[val]); 1122 | value=val 1123 | a=gsub(/_[a-zA-Z0-9]+$/,\"\",val); 1124 | key=val \"$separator\" 1125 | if (!match(keys[key], value))keys[key]=keys[key] \" \" value; 1126 | while(a>0) { 1127 | value=val 1128 | a=gsub(/_[a-zA-Z0-9]+$/,\"\",val); 1129 | ix=index(val,\"$separator\"); 1130 | if (ix>=0) { 1131 | key=val \"$separator\" 1132 | if (!match(keys[key], value))keys[key]=keys[key] \" \" value \"$separator\"; 1133 | } 1134 | } 1135 | } 1136 | for(key in keys) { 1137 | printf(\"%s=\\\"%s\\\"\n\", key, keys[key]); 1138 | } 1139 | }" 1140 | } 1141 | 1142 | 1143 | main "$@" 1144 | --------------------------------------------------------------------------------