Skip to content

Instantly share code, notes, and snippets.

@Binsk
Last active May 11, 2021 22:48
Show Gist options
  • Save Binsk/7eca0b001603515a79348225dce13ae6 to your computer and use it in GitHub Desktop.
Save Binsk/7eca0b001603515a79348225dce13ae6 to your computer and use it in GitHub Desktop.
GameMaker: Studio 2.3 Linux Compiling Interface
#!/bin/bash
# Author: Reuben Shea
# Date: Apr, 09 2021
# This script handles re-compiling a GameMaker project remotely given the
# wine prefix and runtime version. It is merely a convenience script I wrote
# so I could use GMEdit and compile on Linux w/o having to have the engine
# open due to big projects lagging like all hell.
# This script requires that you have opened GM and attempted to compile your
# project at least once. This script will just re-compile based on whatever the
# last compile was. An actual 'build' command is being worked on but I'm not
# there yet.
# Check we aren't in root:
if [ "$EUID" -eq 0 ]; then
printf "This script cannot be run as root\n"
exit 0
fi
# Define colors, if supported:
CB="" # Bold
CN="" # Normal
CI="" # Important
CC="" # Code
CE="" # Error
if [ -n "$(tput colors)" ] && [ "$(tput colors)" -ge 8 ]; then
CB="\e[1m"
CN="\e[0m"
CI="\e[36m"
CS="\e[32m"
CE="\e[31m"
CC="\e[33m"
fi
# Check that necessary packages are installed:
if ! hash wine &> /dev/null; then
printf "This script requires ${CB}wine${CN} as well as 32bit architecture\nenabled in order to run!\n${CI}Please see: https://wiki.winehq.org/download${CN}\n\n"
exit 1;
fi
if ! hash winetricks &> /dev/null; then
printf "This script requires ${CB}winetricks${CN} in order to run!\n${CI}Please see: https://wiki.winehq.org/winetricks${CN}\n\n"
exit 1;
fi
# Define default values:
HOME=$(printf ~/)
PREFIX_GMS="${HOME}.wine" # Prefix of GameMaker installation
RUNTIME_GMS="" # Runtime version (last if blank)
PREFIX_SHELL="${HOME}.wine_gmbuild" # Personall 'shell' prefix for running the game
PROJECT_PATH="" # NOT YET SUPPORTED
COMPILE_SILENT=0
WINE_DEBUG_STRING="env WINEDEBUG='warn-all,fixme-all,trace-all,err-all'"
# Define our functions:
# Usage: FNC_display_help
FNC_display_help(){
printf "Usage: gmbuild [ACTION] [OPTION]...\n"
printf "Build, run, or clean a GMS project from terminal.\n"
printf "\nIf no runtime or prefix is specified then the system\nwill use the latest avialable runtime and default\nwine prefix.\n"
printf "\nActions:\n"
printf "\trun\t\t\tRuns the active project in the specified prefix\n\t\t\t\tbased on previous build settings\n"
printf "\tbuild\t\t\tBuilds and runs a project in the specified prefix\n\t\t\t\tbased on the currently specified project path\n"
printf "\tclean\t\t\tCleans the project\n"
printf "\tkill\t\t\tKills any detached WINE processes in the\n\t\t\t\tprefix left from the previous run\n"
printf "\tlist\t\t\tLists available installed runtimes for the \n\t\t\t\tcurrent prefix\n"
printf "\tprintle\t\t\tPrints the last recorded runtime error\n"
printf "\tuninstall\t\tDestroys the WINE prefix auto-generated by\n\t\t\t\tthis script and any saved project settings\n"
printf "\nIf no action is provided then the system will boot into\nan interactive mode.\n"
printf "\nOptions:\n"
printf "\t-h, --help\t\t\tDisplay this help page\n"
printf "\t-r, --runtime=RUNTIME\t\tSpecify RUNTIME as the runtime version to use\n"
printf "\t-p, --prefix=PREFIX\t\tSpecify PREFIX as the active WINE prefix\n"
printf "\t-l, --load=PROJECT\t\tSpecify to load saved prefix and runtime values\n\t\t\t\t\tfor PROJECT\n"
printf "\t-wv, --wine-verbose\t\tEnable verbose WINE output\n"
printf "\t-s, --silent\t\t\tDisable all compliing output\n"
printf "\nTo save project settings for quick building, launch in\ninteractive mode, set your prefix and\nruntime, then type 'save' to store the settings.\n"
printf "\nExamples:\n"
printf "\tgmbuild list\t\t\t\n"
printf "\tgmbuild run -r \"2.3.2.420\" -p \"/home/\$USER/.wine\"\n"
printf "\tgmbuild kill\n"
printf "\tgmbuild run --load=DemoProject\n"
printf "\n"
}
# Usage: FNC_prefix_setup
FNC_prefix_setup(){
printf "A special WINE prefix is required to run this script.\n";
printf "This can take a while and requires an internet connection.\n\n"
printf "Would you like to set this up now? [Y/n]: "
read INPUT
if [ "$INPUT" != "" ] && [ "$INPUT" != "y" ] && [ "$INPUT" != "Y" ]; then
printf "Received negative response. Exiting...\n"
exit 0
fi
printf "\nGenerating prefix...\n"
env WINEPREFIX="$PREFIX_SHELL" WINEARCH="win64" winetricks dotnet48 --force -q
env WINEPREFIX="$PREFIX_SHELL" wineserver -w
printf "\nPrefix generated!\n"
}
# Usage: FNC_save [name]
FNC_save(){
if [ -f "${HOME}.gmbuild" ]; then
FILE=$(cat "${HOME}.gmbuild")
rm "${HOME}.gmbuild" &> /dev/null
for LINE in $FILE; do
if [ "$LINE" = "" ]; then
continue
fi
$MATCH=$(printf "$LINE" | grep -o -E "\[$1:(prefix|runtime)\]")
if [ "$MATCH" = "" ]; then
printf "$LINE\n" >> "${HOME}.gmbuild"
fi
done
fi
printf "[$1:prefix]=$PREFIX_GMS\n" >> "${HOME}.gmbuild"
printf "[$1:runtime]=$RUNTIME_GMS\n" >> "${HOME}.gmbuild"
}
# Usage: FNC_load [name]
FNC_load(){
if [ ! -f "${HOME}.gmbuild" ]; then
printf "No settings file found\n"
return
fi
PFX=$(cat "${HOME}.gmbuild" | grep -E "\[$1\:prefix]" | sed -r "s/[^=]+=//")
RT=$(cat "${HOME}.gmbuild" | grep -E "\[$1\:runtime]" | sed -r "s/[^=]+=//")
if [ "$PFX" = "" ]; then
printf " Failed to load: No settings found for '$1'\n"
return
fi
if [ "$PFX" = "$PREFIX_SHELL" ] || [ ! -d "$PFX/drive_c/" ]; then
printf " Failed to load: Invalid WINE prefix\n"
printf "${PFX}\n"
return
fi
if [ ! -d "$PREFIX_GMS/drive_c/ProgramData/GameMakerStudio2/Cache/runtimes/runtime-$RT" ] && [ "$RT" != "" ]; then
printf " Failed to load: Invalid runtime\n"
return
fi
PREFIX_GMS=$PFX
RUNTIME_GMS=$RT
printf " Loaded project settings for '$1'\n"
}
# Usage: FNC_read_json [file] [key]
FNC_read_json(){
while read LINE; do
VALUE=$(grep "\"${2}\"" "${1}" | sed -r 's/^ *//;s/.*: *"//;s/",?//')
if [ "$VALUE" ]; then
printf "$VALUE"
return
fi
done < "$1"
}
# Usage: FNC_get_input [input]
# Sets two variables:
# 1. INPUT - Regular user input
# 2. SPECIAL - Name of special input (such as ARRLEFT)
FNC_get_input(){
IFS_O=$IFS
IFS=
INPUT="${1}"
SPECIAL=""
CHARCOUNT=${#1}
while read -sn1 PREINPUT; do
case "$PREINPUT" in
$'\x1b')
read -sn1 PREINPUT
if [ "$PREINPUT" == "[" ]; then
read -sn1 PREINPUT
case "$PREINPUT" in
"A") SPECIAL="ARRUP"; break;;
"B") SPECIAL="ARRDOWN"; break;;
"C") SPECIAL="ARRRIGHT"; break;;
"D") SPECIAL="ARRLEFT"; break;;
esac
fi
;;
$'\177')
if [ "$CHARCOUNT" -gt 0 ]; then
echo -en "\b \b"
CHARCOUNT=$((CHARCOUNT-1))
INPUT="${INPUT:0:${#INPUT}-1}"
fi
;;
"")break;;
*)
CHARCOUNT=$((CHARCOUNT+1))
printf %s "$PREINPUT"
INPUT="${INPUT}${PREINPUT}"
;;
esac
done
IFS=$IFS_O
}
# Usage: var=FNC_get_runtime
FNC_get_runtime(){
OPATH=$PWD
FPATH="$PREFIX_GMS/drive_c/ProgramData/GameMakerStudio2/Cache/runtimes" 2> /dev/null
RT=""
if [ -d "$FPATH" ]; then
cd "$FPATH"
FILES=(*)
for DIR in ${FILES[@]}; do
RT="$(printf "$DIR" | sed -r "s/runtime-//")"
done
cd "$OPATH"
fi
printf "$RT"
}
# Usage: FNC_list_runtimes
FNC_list_runtimes(){
printf " Searching in prefix: $PREFIX_GMS\n"
OPATH=$PWD
FPATH="$PREFIX_GMS/drive_c/ProgramData/GameMakerStudio2/Cache/runtimes" 2> /dev/null
if [ -d "$FPATH" ]; then
cd "$FPATH"
FILES=(*)
for DIR in ${FILES[@]}; do
printf " $DIR\n" | sed "s/runtime-//"
done
cd "$ODIR"
else
printf " No runtimes found!\n\n Please compile with GMS once first and\n make sure you are in the correct prefix.\n"
fi
}
# Usage: FNC_create_symlinks
FNC_create_symlinks(){
if [ -d "$PREFIX_SHELL/drive_c/ProgramData/GameMakerStudio2" ]; then
return
fi
ln -s "$PREFIX_GMS/drive_c/users/$USER/Application Data/GameMakerStudio2" "$PREFIX_SHELL/drive_c/users/$USER/Application Data/"
ln -s "$PREFIX_GMS/drive_c/ProgramData/GameMakerStudio2" "$PREFIX_SHELL/drive_c/ProgramData"
ln -s "$PREFIX_GMS/drive_c/Program Files/GameMaker Studio 2" "$PREFIX_SHELL/drive_c/Program Files/"
}
#Usage: FNC_delete_symlinks
FNC_delete_symlinks(){
rm "$PREFIX_SHELL/drive_c/users/$USER/Application Data/GameMakerStudio2" &> /dev/null
rm "$PREFIX_SHELL/drive_c/ProgramData/GameMakerStudio2" &> /dev/null
rm "$PREFIX_SHELL/drive_c/Program Files/GameMaker Studio 2" &> /dev/null
}
FNC_printle(){
if [ ! -f "${HOME}.gmbuild_log" ]; then
printf " No build log found\n"
return
fi
if ! hash perl &> /dev/null; then
printf " Could not find PERL! Using backup method...\n"
FNC_printle_backup
return
fi
perl -e '
open(FILE, "<", "$ARGV[0].gmbuild_log");
@output=();
$CN = "$ARGV[1]";
$CI = "$ARGV[2]";
$CE = "$ARGV[3]";
$CB = "$ARGV[4]";
$CC = "$ARGV[5]";
$ERROR_STATE = 0;
$ERROR_FOUND = 0;
while (<FILE>){
$LINE="$_";
if ($ERROR_STATE == 0 && $LINE =~ /^ERROR!!! :: ###/){
$ERROR_STATE = 2;
$ERROR_FOUND = 1;
push(@output, "$CI$CB ERROR:\n ==================================$CN\n");
$LINE="";
}
elsif ($ERROR_STATE == 2 && $LINE =~ /^############/){
$ERROR_STATE = 1;
$LINE="";
push(@output, "\n ${CI}${CB}STACK TRACE:\n${CN}");
}
elsif ($ERROR_STATE == 1 && $LINE !~ /^gml_/){
$ERROR_STATE = 0;
push(@output, "$CI$CB ==================================$CN\n");
$LINE="";
}
else{
if ($ERROR_STATE == 2){
$LINE =~ s/\t+//g;
$LINE =~ s/(\w+) Event/$CI\1$CN Event/;
$LINE =~ s/^for (\w+) ([^:]+)/for \1 $CI\2$CN/;
$LINE =~ s/\(line ([0-9]+)/(${CI}line \1$CN/;
$LINE =~ s/^(at )?gml_([^_]+)/\1gml_$CI\2$CN/;
push(@output, " $LINE");
}
elsif ($ERROR_STATE == 1){
$LINE =~ s/\t+//g;
$LINE =~ s/\(line ([0-9]+)/(${CI}line \1${CN}/;
$LINE =~ s/^gml_([^_]+)/gml_${CI}\1${CN}/;
$LINE =~ s/\-(.*)$/-${CC}\1${CN}/;
push(@output, " $LINE");
}
elsif ($LINE =~ /^Error/){
$LINE =~ s/^Error/${CE}Error${CN}/;
$LINE =~ s/\(([^)]+)\)/(${CI}\1${CN})/g;
$ERROR_FOUND = 1;
push(@output, " $LINE");
}
}
}
print(@output);
if ($ERROR_FOUND == 0){
print(" No errors!\n");
}
exit;
' -- "${HOME}" $(printf $CN) $(printf $CI) $(printf $CE) $(printf $CB) $(printf $CC)
}
#Usage: FNC_printle
FNC_printle_backup(){
ERROR_STATE=0 # Current error checking state
ERROR_FOUND=0 # Bool if we found an error
STACK_TRACE=() # Stack trace of last error
LINE_NUM=1
LINE_COUNT=$(wc -l "${HOME}.gmbuild_log" | grep -o -E "[0-9]+")
LAST_STRING=""
if [ "$LINE_COUNT" -gt 1000 ]; then
printf " Log is $LINE_COUNT lines long and could take a long time. Proceed? [Y/n]: "
read INPUT
if [ "$INPUT" != "" ] && [ "$INPUT" != "y" ] && [ "$INPUT" != "Y" ]; then
return
fi
fi
while read LINE; do
# We came across an error:
if [ "$ERROR_STATE" -eq 0 ] && [ "$(printf %s "$LINE" | grep -E -o "^ERROR!!! :: ###")" != "" ]; then
ERROR_STATE=2
ERROR_FOUND=1
printf " ${CI}${CB}ERROR:\n ==================================\n\n${CN}"
continue
fi
# We came across the end of the error message (but not the stack trace)
if [ "$ERROR_STATE" -eq 2 ] && [ "$(printf %s "$LINE" | grep -E -o "^############")" != "" ]; then
ERROR_STATE=1
STACK_TRACE=() # Prepare to store new stack trace
continue
fi
# We came across the end of the error. Print the stack trace:
if [ "$ERROR_STATE" -eq 1 ] && [ "$(printf %s "$LINE" | grep -E -o "^gml_")" = "" ]; then
ERROR_STATE=0
# Only print if we have a stack trace:
if [ ${#STACK_TRACE[@]} -gt 0 ]; then
printf "\n ${CI}${CB}STACK TRACE:\n${CN}"
for (( i=0; i<${#STACK_TRACE[@]}; i++ )); do
LINE="${STACK_TRACE[$i]}"
LINE="$(printf "$LINE" | sed -r "s/\t+//g")"
LINE="$(printf "$LINE" | sed -r "s/\(line ([0-9]+)/(\\${CI}line \1\\${CN}/")"
LINE="$(printf "$LINE" | sed -r "s/^gml_([^_]+)/gml_\\${CI}\1\\${CN}/")" # Resource type
LINE="$(printf "$LINE" | sed -r "s/\-(.*)$/-\\${CC}\1\\${CN}/")"
printf " $LINE\n"
done
fi
printf "${CI}${CB}\n ==================================\n${CN}"
LAST_LINE=""
continue;
fi
# Print regular error line:
if [ "$ERROR_STATE" -gt 0 ]; then
if [ "$ERROR_STATE" -eq 2 ]; then
LINE="$(printf "$LINE" | sed -r "s/\t+//g")" # Remove excess tabs
LINE="$(printf "$LINE" | sed -r "s/(\w+) Event/\\${CI}\1\\${CN} Event/")" #Name of event
LINE="$(printf "$LINE" | sed -r "s/^for (\w+) ([^:]+)/for \1 \\${CI}\2\\${CN}/")" # Name of object
LINE="$(printf "$LINE" | sed -r "s/\(line ([0-9]+)/(\\${CI}line \1\\${CN}/")" # Line number
LINE="$(printf "$LINE" | sed -r "s/^(at )?gml_([^_]+)/\1gml_\\${CI}\2\\${CN}/")" # Resource type
printf " $LINE\n"
LAST_LINE=""
else
STACK_TRACE+=("$LINE")
fi
else
if [ "$(printf %s "$LINE" | grep -E -o "^Error")" != "" ]; then
TMP="$(printf "$LINE" | sed -r "s/^Error/\\${CE}Error\\${CN}/")"
TMP="$(printf "$TMP" | sed -r "s/\(([^)]+)\)/(\\${CI}\1\\${CN})/g")"
printf "\n $TMP\n"
LAST_LINE=""
ERROR_FOUND=1
else
for C in $(seq 0 $(printf "$LAST_LINE" | sed -r "s/(.)/\1\n/g" | grep -c -E ".")); do
echo -en "\b"
done
LAST_LINE=" Line: $LINE_NUM / $LINE_COUNT"
printf %s "$LAST_LINE"
fi
fi
LINE_NUM=$((LINE_NUM+1))
# -- STUB -- # Add support for detecting [WARNING] lines, etc
done < "${HOME}.gmbuild_log"
# Check if we had errors for our final message:
if [ "$ERROR_FOUND" -eq 0 ]; then
printf "\n No errors!"
fi
printf "\n"
}
# Usage: FNC_build
FNC_build(){
DISPLAY_WARNING=0
printf "${CE}\n====================\n"
printf "TODO: Not implemented yet!\n"
printf "====================\n${CN}"
FPATH="$PREFIX_GMS/drive_c/users/$USER/Application Data/GameMakerStudio2/"
UMPATH="${FPATH}um.json"
if [ ! -f "$UMPATH" ]; then
printf "Failed to locate user properties file\n"
return
fi
# Select a default runtime if none set:
if [ "$RUNTIME_GMS" = "" ]; then
RUNTIME_GMS=$(FNC_get_runtime)
fi
USERID="$(FNC_read_json "$UMPATH" "userID")"
UNAME="$(FNC_read_json "$UMPATH" "username")"
UNAME="$(printf "$UNAME" | grep -o -E "^[^@]+")"
#Z_PROJECT_PATH="$(printf %s "Z:$PROJECT_PATH" | sed -r "s/\//\\\^/g" | sed -r "s/\\^/\\\/g")"
#NAME="$(printf "$PROJECT_PATH" | grep -E -o "([^/]+)\.yyp$" | sed -r "s/\.yyp//")"
#TEMP="C:\\\\users\\\\$USER\\\\Application Data\\\\GameMakerStudio2\\\\Temp\\\\GMS2TEMP"
#UPATH="C:\\\\users\\\\$USER\\\\Application Data\\\\GameMakerStudio2\\\\${UNAME}_${USERID}"
#CFG="Default"
#OPATH="C:\\\\users\\\\$USER\\\\Application Data\\\\GameMakerStudio2\\\\Temp\\\\GMS2TEMP"
#BPATH="C:\\\\ProgramData\\\\GameMakerStudio2\\\\Cache\\\\runtimes\\\\runtime-$RUNTIME_GMS\\\\BaseProject\\\\BaseProject.yyp"
Z_PROJECT_PATH="Z:$PROJECT_PATH"
# Generate random string for output folder name
RANDOM_STRING=""
RANDOM_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
for i in {1..16} ; do
RANDOM_STRING=$(printf %s "${RANDOM_STRING}${RANDOM_CHARS:RANDOM%${#RANDOM_CHARS}:1}")
done
# Generate parameter strings:
NAME="$(printf "$PROJECT_PATH" | grep -E -o "([^/]+)\.yyp$" | sed -r "s/\.yyp//")"
TEMP="C:/users/$USER/Application Data/GameMakerStudio2/Temp/GMS2TEMP/"
UPATH="C:/users/$USER/Application Data/GameMakerStudio2/${UNAME}_${USERID}/"
CFG="Default"
OPATH="${TEMP}${NAME}_$RANDOM_STRING"
BPATH="C:/ProgramData/GameMakerStudio2/Cache/runtimes/runtime-$RUNTIME_GMS/BaseProject/BaseProject.yyp"
printf "${CI}\n====================\n"
printf %s "Project Path: $Z_PROJECT_PATH"
printf "\n"
printf %s "Project Name: $NAME"
printf "\n"
printf %s "Temp Path: $TEMP"
printf "\n"
printf %s "User Path: $UPATH"
printf "\n"
printf %s "Output Path: $OPATH"
printf "\n"
printf %s "Base Project Path: $BPATH"
printf "\n"
printf %s "Config: $CFG"
printf "\n====================\n\n${CN}"
if [ ! -f "$PROJECT_PATH" ]; then
printf "Failed to locate project: '$PROJECT_PATH'\n"
return
fi
DISPLAY_WARNING=1
if [ "$COMPILE_SILENT" -eq 0 ]; then
(env WINEPREFIX="$PREFIX_SHELL" wine "$PREFIX_GMS/drive_c/ProgramData/GameMakerStudio2/Cache/runtimes/runtime-$RUNTIME_GMS/bin/GMAssetCompiler.exe" /c /mv=1 /iv=0 /rv=0 /bv=0 /zpex /j=8 /gn="$NAME" /td="$TEMP" /zpuf="$UPATH" /m=windows /tgt=64 /nodnd /cfg="$CFG" /o="$OPATH" /sh=True /cvm /baseproject="$BPATH" "$Z_PROJECT_PATH" /v /bt=run -v -- Windows Run) | tee "${HOME}.gmbuild_log"
else
(env WINEPREFIX="$PREFIX_SHELL" wine "$PREFIX_GMS/drive_c/ProgramData/GameMakerStudio2/Cache/runtimes/runtime-$RUNTIME_GMS/bin/GMAssetCompiler.exe" /c /zpex /j=8 /gn="$NAME" /td="$TEMP" /zpuf="$UPATH" /m=windows /tgt=64 /nodnd /cfg="$CFG" /o="$OPATH" /sh=True /cvm /baseproject="$BPATH" "$Z_PROJECT_PATH" /v /bt=run -v -- Windows Run) | tee "${HOME}.gmbuild_log" &>/dev/null
fi
}
# Usage: FNC_run
FNC_run(){
DISPLAY_WARNING=0
if [ ! -d "$PREFIX_GMS" ]; then
printf " Invalid WINE prefix\n"
return
fi
if [ ! -d "$PREFIX_GMS/drive_c/ProgramData/GameMakerStudio2/" ]; then
printf " Could not find GameMaker: Studio 2.x installation\n"
return
fi
if [ "$RUNTIME_GMS" = "" ]; then
RUNTIME_GMS=$(FNC_get_runtime)
fi
FNC_create_symlinks # Make sure our prefix links to the right temp directories
printf "${CI}\n ====================\n"
printf " Running with runtime: $RUNTIME_GMS\n"
printf " Running in prefix: $PREFIX_GMS\n"
printf " ====================\n\n${CN}"
DISPLAY_WARNING=1
if [ "$COMPILE_SILENT" -eq 0 ]; then
(env WINEPREFIX="$PREFIX_SHELL" $WINE_DEBUG_STRING wine "$PREFIX_GMS/drive_c/ProgramData/GameMakerStudio2/Cache/runtimes/runtime-$RUNTIME_GMS/bin/Igor.exe" -j=8 -options="C:\\users\\$USER\\Application Data\\GameMakerStudio2\\Temp/GMS2TEMP\\build.bff" -v -- Windows Run) | tee "${HOME}.gmbuild_log"
else
(env WINEPREFIX="$PREFIX_SHELL" $WINE_DEBUG_STRING wine "$PREFIX_GMS/drive_c/ProgramData/GameMakerStudio2/Cache/runtimes/runtime-$RUNTIME_GMS/bin/Igor.exe" -j=8 -options="C:\\users\\$USER\\Application Data\\GameMakerStudio2\\Temp/GMS2TEMP\\build.bff" -v -- Windows Run) | tee "${HOME}.gmbuild_log" &> /dev/null
fi
}
# Usage: FNC_clean
FNC_clean(){
FNC_create_symlinks
if [ "$RUNTIME_GMS" = "" ]; then
RUNTIME_GMS=$(FNC_get_runtime)
fi
printf "${CI}\n ====================\n"
printf " Running with runtime: $RUNTIME_GMS\n"
printf " Running in prefix: $PREFIX_GMS\n"
printf " ====================\n\n${CN}"
(env WINEPREFIX="$PREFIX_SHELL" $WINE_DEBUG_STRING wine "$PREFIX_GMS/drive_c/ProgramData/GameMakerStudio2/Cache/runtimes/runtime-$RUNTIME_GMS/bin/Igor.exe" -j=8 -options="C:\\users\\$USER\\Application Data\\GameMakerStudio2\\Temp/GMS2TEMP\\build.bff" -v -- Windows Clean) 2> /dev/null
printf " Project cleaned...\n"
}
# Usage: FNC_uninstall
FNC_uninstall(){
rm -R "$PREFIX_SHELL/" &> /dev/null
rm -R "/home/$USER/.gmbuild" &> /dev/null
rm "${HOME}.gmbuild_log" &> /dev/null
rm "${HOME}.gmbuild_history" &> /dev/null
printf " Files removed\n"
}
# Usage: FNC_kill_wineserver
FNC_kill_wineserver(){
env WINEPREFIX="$PREFIX_SHELL" wineserver -k &> /dev/null
}
# Usage: FNC_interactive_mode
FNC_interactive_mode(){
printf "Entering interactive program, type 'exit' to terminate.\n"
printf "Available commands are:\t${CI}exit, help, run, clean, build, kill,\n\t\t\tset, get, list, save, load, printle,\n\t\t\tuninstall${CN}\n"
printf "; "
FINISHED=0
LAST_COMMAND=""
LAST_INPUT=""
HISTORY_INDEX=0
while [ "$FINISHED" -eq 0 ]; do
FNC_get_input "$LAST_INPUT"
PREINPUT="$INPUT"
# Handle basic up/down shortcuts:
case "$SPECIAL" in
"ARRUP")
if [ "$(ls "${HOME}" -a | grep ".gmbuild_history" -c)" -eq 0 ]; then
LAST_INPUT=""
continue
fi
HISTORY_INDEX=$((HISTORY_INDEX+1))
LINE_COUNT=$(wc -l "${HOME}.gmbuild_history" | sed -r "s/[^0-9]//g")
if [ "$HISTORY_INDEX" -gt $((LINE_COUNT)) ]; then
HISTORY_INDEX=$((LINE_COUNT))
fi
for (( i=0; i < ${#INPUT}; ++i )); do
echo -en "\b \b"
done
LAST_INPUT="$(tac "${HOME}.gmbuild_history" | head -n${HISTORY_INDEX} | tail -n1 2> /dev/null)"
printf "$LAST_INPUT"
continue
;;
"ARRDOWN")
if [ "$(ls "${HOME}" -a | grep ".gmbuild_history" -c)" -eq 0 ]; then
LAST_INPUT=""
continue
fi
HISTORY_INDEX=$((HISTORY_INDEX-1))
if [ "$HISTORY_INDEX" -lt 0 ]; then
HISTORY_INDEX=0
fi
for (( i=0; i < ${#INPUT}; ++i )); do
echo -en "\b \b"
done
if [ "$HISTORY_INDEX" -eq 0 ]; then
LAST_INPUT=""
else
LAST_INPUT="$(tac "${HOME}.gmbuild_history" | head -n${HISTORY_INDEX} | tail -n1 2> /dev/null)"
printf "$LAST_INPUT"
fi
continue
;;
"")
if [ "$INPUT" != "" ]; then
printf "$INPUT\n" >> "${HOME}.gmbuild_history"
fi
LAST_INPUT=""
HISTORY_INDEX=0
printf "\n"
;;
*)
FNC_strlen "$INPUT"
for (( i=0; i < $LEN; ++i )); do
echo -en "\b \b"
done
LAST_INPUT=""
HISTORY_INDEX=0
continue;;
esac
SETTO="" # Used if we find an equal sign
COMBINED_INPUT="$(printf "${LAST_COMMAND}${INPUT}" | sed "s/\s\s/\s/g")"
PREPEND=""
if [ "$(printf "$COMBINED_INPUT" | grep -o "=")" = "=" ]; then
INPUT="$(printf "$COMBINED_INPUT" | sed -r "s/^([^=]+)=.*$/\1/")"
SETTO="$(printf "$COMBINED_INPUT" | sed -r "s/[^=]+=(.*)$/\1/")"
SETTO="$(printf "$SETTO" | sed "s/^\s+//")"
SETTO="$(printf "$SETTO" | sed "s/\s+$//")"
else
INPUT="$COMBINED_INPUT"
fi
INPUT="$(printf "$INPUT" | sed "s/^\s+//")"
INPUT="$(printf "$INPUT" | sed "s/\s+$//")"
if [ "$INPUT" = "exit" ] || [ "$INPUT" = "quit" ]; then
FINISHED=1
continue
elif [ "$INPUT" = "kill" ]; then
FNC_kill_wineserver
printf " Server killed...\n"
LAST_COMMAND=""
elif [ "$INPUT" = "help" ]; then
FNC_display_help
LAST_COMMAND=""
elif [ "$INPUT" = "list" ]; then
FNC_list_runtimes
LAST_COMMAND=""
elif [ "$INPUT" = "set" ]; then
printf " Available set options:\n"
printf " \tprefix\n"
printf " \truntime\n"
PREPEND="set "
LAST_COMMAND="set "
elif [ "$INPUT" = "set runtime" ]; then
RT=""
if [ "$SETTO" != "" ]; then
RT=$SETTO
else
printf "; set runtime="
read RT
fi
if [ ! -d "$PREFIX_GMS/drive_c/ProgramData/GameMakerStudio2/Cache/runtimes/runtime-$RT" ]; then
printf " Invalid runtime\n"
else
RUNTIME_GMS=$RT
printf " Set runtime to '$RT'\n"
fi
LAST_COMMAND=""
elif [ "$INPUT" = "set prefix" ]; then
FNC_kill_wineserver
FNC_delete_symlinks
PFX=""
if [ "$SETTO" != "" ]; then
PFX=$SETTO
else
printf "; set prefix="
read PFX
fi
if [ "$PFX" = "$PREFIX_SHELL" ] || [ ! -d "$PFX/drive_c" ]; then
printf " Invalid prefix\n"
else
PREFIX_GMS=$PFX
printf " Set prefix to '$PFX'\n"
fi
LAST_COMMAND=""
elif [ "$INPUT" = "printle" ]; then
FNC_printle
LAST_COMMAND=""
elif [ "$INPUT" = "get" ]; then
printf " Available get options:\n"
printf " \tprefix\n"
printf " \truntime\n"
PREPEND="get "
LAST_COMMAND="get "
elif [ "$INPUT" = "get runtime" ]; then
RT=$RUNTIME_GMS
if [ "$RUNTIME_GMS" = "" ]; then
RT=$(FNC_get_runtime)
fi
if [ "$RT" = "" ]; then
printf " No runtimes found!\n\n Please compile with GMS once first and\n make sure you are in the correct prefix.\n"
else
printf " Current runtime is '$RT'\n"
fi
LAST_COMMAND=""
elif [ "$INPUT" = "get prefix" ]; then
printf " Current prefix is '$PREFIX_GMS'\n"
LAST_COMMAND=""
elif [ "$INPUT" = "run" ]; then
FNC_kill_wineserver
FNC_run
LAST_COMMAND=""
elif [ "$INPUT" = "build" ]; then
FNC_kill_wineserver
FNC_build
LAST_COMMAND=""
elif [ "$INPUT" = "clean" ]; then
FNC_kill_wineserver
FNC_clean
LAST_COMMAND=""
elif [ "$INPUT" = "uninstall" ]; then
FNC_kill_wineserver
FNC_uninstall
LAST_COMMAND=""
elif [ "$INPUT" = "load" ]; then
printf " This will load and overwrite project settings. Continue? [Y/n]: "
read INPUT
if [ "$INPUT" != "Y" ] && [ "$INPUT" != "y" ] && [ "$INPUT" != "" ]; then
printf " Received negative response\n"
else
printf "; load project="
read INPUT
FNC_load "$INPUT"
fi
LAST_COMMAND=""
elif [ "$INPUT" = "save" ]; then
printf " This will save current project settings. Contine? [Y/n]: "
read INPUT
if [ "$INPUT" != "Y" ] && [ "$INPUT" != "y" ] && [ "$INPUT" != "" ]; then
printf " Received negative response\n"
else
printf "; save project="
read INPUT
FNC_save "$INPUT"
fi
LAST_COMMAND=""
elif [ "$PREINPUT" = "" ]; then
if [ "$LAST_COMMAND" != "" ]; then
printf " $LAST_COMMAND cleared...\n"
fi
LAST_COMMAND=""
else
printf " Invalid command\n"
LAST_COMMAND=""
fi
printf "; $PREPEND"
done
}
# Process input arguments:
LAST_ARG=""
CMD=""
for ARG in "$@"; do
PROC=1
if [ "$LAST_ARG" = "" ]; then
PROC=0
DD="$(printf %s "$ARG" | grep -o -E "^--[a-zA-Z]+=" | grep -o -E "[^=]+")"
if [ "$ARG" = "-r" ] || [ "$ARG" = "--runtime" ] || [ "$DD" = "--runtime" ]; then
LAST_ARG="-r"
if [ "$DD" = "--runtime" ]; then
ARG="$(printf %s "$ARG" | grep -o -E "=[^=]+" | grep -o -E "[^=]+")"
PROC=1
fi
elif [ "$ARG" = "-p" ] || [ "$ARG" = "--prefix" ] || [ "$DD" = "--prefix" ]; then
LAST_ARG="-p"
if [ "$DD" = "--prefix" ]; then
ARG="$(printf %s "$ARG" | grep -o -E "=[^=]+" | grep -o -E "[^=]+")"
PROC=1
fi
elif [ "$ARG" = "-l" ] || [ "$ARG" = "--load" ] || [ "$DD" = "--load" ]; then
LAST_ARG="-l"
if [ "$DD" = "--load" ]; then
ARG="$(printf %s "$ARG" | grep -o -E "=[^=]+" | grep -o -E "[^=]+")"
PROC=1
fi
elif [ "$ARG" = "-h" ] || [ "$ARG" = "--help" ]; then
FNC_display_help
exit 0
elif [ "$ARG" = "-wv" ] || [ "$ARG" = "--wine-verbose" ]; then
WINE_DEBUG_STRING=""
elif [ "$ARG" = "-s" ] || [ "$ARG" = "--silent" ]; then
COMPILE_SILENT=1
elif [ "$CMD" = "" ]; then
CMD="$ARG"
fi
fi
if [ "$PROC" -eq 1 ]; then
if [ "$LAST_ARG" = "-r" ]; then
RUNTIME_GMS=$ARG
LAST_ARG=""
elif [ "$LAST_ARG" = "-p" ]; then
FNC_delete_symlinks
if [ "$ARG" = "$PREFIX_SHELL" ] || [ ! -d "$ARG/drive_c" ]; then
printf "Invalid prefix\n"
continue
fi
PREFIX_GMS=$ARG
LAST_ARG=""
elif [ "$LAST_ARG" = "-l" ]; then
FNC_load $ARG
LAST_ARG=""
else
FNC_display_help
kill 0
fi
fi
done
# Test if our prefix has been set up:
if [ ! -d "$PREFIX_SHELL" ]; then
FNC_prefix_setup
fi
FNC_delete_symlinks
rm "${HOME}.gmbuild_history" &> /dev/null
# Execute stored commands:
if [ "$CMD" = "run" ]; then
FNC_run
if [ "$DISPLAY_WARNING" = "1" ]; then
printf "${CI}\n====================\n"
printf "You may need to manually kill the server!\n"
printf "Type 'gmbuild kill' after you close your build.\n"
printf "====================\n\n${CN}"
fi
elif [ "$CMD" = "build" ]; then
FNC_build
if [ "$DISPLAY_WARNING" = "1" ]; then
printf "${CI}\n====================\n"
printf "You may need to manually kill the server!\n"
printf "Type 'gmbuild kill' after you close your build.\n"
printf "====================\n\n${CN}"
fi
elif [ "$CMD" = "clean" ]; then
rm "${HOME}.gmbuild_log" &> /dev/null # Destroy any old logs
FNC_clean
elif [ "$CMD" = "kill" ]; then
FNC_kill_wineserver
printf "Server killed...\n"
elif [ "$CMD" = "list" ]; then
FNC_list_runtimes
elif [ "$CMD" = "uninstall" ]; then
FNC_kill_wineserver
FNC_uninstall
elif [ "$CMD" = "printle" ]; then
FNC_printle
elif [ "$CMD" = "" ]; then
rm "${HOME}.gmbuild_log" &> /dev/null # Destroy any old logs
FNC_interactive_mode
FNC_kill_wineserver
else
FNC_display_help
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment