#!/bin/sh

# This is a shell script roughly reproducing the behavior of
# GoopSwagger's quickprecache java program with the -auto option,
# available at <https://github.com/Lucifixion/QuickPrecache>.
# This makes their preloader mod usable on Linux, providing the
# user sets up the needed environement variables, has a Windows
# installation of TF2 somewhere on their system with studiomdl and
# compiles+installs vpkex, a utility to print the content of VPK
# files. This script need not be at the root of your TF2
# installation.
#
# Some liberties were taken that make this script diverge a bit
# from the original program: generated precache_* MDL files are
# saved to tf/custom/quickprecache_gen/models/ rather than tf/models/
# directly, and a special file "quickprecache_ignore.txt" can be
# created in tf/custom/ and filled with regexes whose matches will
# be ignored by the script. Examples of such regexes can be:
#
# mod/path/to/model.mdl
# mod.vpk/path/to/model.mdl
# model.mdl
#
# But notice that the last example will remove *all* models named
# "model.mdl" due to how regexes work. Only POSIX-Extended regular
# expressions will work.
#
# Setup:
# The variables $LINUXTF2DIR and $WINTF2DIR must be set up to
# point to the root of the Linux TF2 installation that is in use
# and to the root of the Windows TF2 installation, respectively.
# I personally set up those variables in "~/.profile".
# 'export LINUXTF2DIR="$HOME/games/SteamLibrary/steamapps/common/Team Fortress 2/"'
# is my declaration of $LINUXTF2DIR. Of course, the path will be
# different for you.
#
# Dependencies:
# - wine
# - vpkex <https://github.com/eXeC64/vpkex>


[ -z "$LINUXTF2DIR" ] && {
	echo "$0: variable \$LINUXTF2DIR not set. This must point to your own TF2 installation."
	exit 1
}
[ -z "$WINTF2DIR" ] && {
	echo "$0: variable \$WINTF2DIR not set. This must point to the root of a Windows TF2 installation."
	exit 1
}

LIST='/tmp/quickprecache.txt'
QC='/tmp/quickprecache.qc'
SAVE='/tmp/quickprecache.save'
IGNOREF="$LINUXTF2DIR/tf/custom/quickprecache_ignore.txt"
MODELSD="$LINUXTF2DIR/tf/custom/quickprecache_gen"
PARTITIONSZ=40
IFS='
'

compile()
{
	relpath="$(realpath --relative-to="$WINTF2DIR" "$1")"
	(
		cd "$WINTF2DIR" && wine ./bin/studiomdl.exe -nop4 -verbose -game ./tf "$relpath"
	)
}

getmodels()
{
	#awk: remove empty lines
	regex="$(cat "$IGNOREF" 2>/dev/null | awk 'NF')"
	[ -z "$regex" ] && regex='^$'

	for i in "$LINUXTF2DIR/tf/custom/"*; do
		if [ -d "$i" ]; then
			find "$i" -name "*.mdl" | sed "s:$i/\(.*\):$(basename "$i")/\1:g"
		elif [ "${i##*.}" = "vpk" ]; then
			vpkex "$i" | grep ".mdl$" | sed "s:^:$(basename "$i")/:g"
		fi
	#paths look like "mod[.vpk]/foo/bar.mdl" so that they can be
	#matched against the ignore file.
	done | grep -vE "$regex
competitive_badge.mdl
decompiled
c_models/animations/" | sed 's:[^/]*/models/::g'
}


[ -d "$MODELSD" ] && rm -r "$MODELSD"
mdls="$(getmodels)"
printf '%s\n' "$mdls" >"$LIST"

echo "Precached models:"
cat "$LIST"

n=0
while [ -s "$LIST" ]; do
	printf '$modelname "precache_%d.mdl"\n' "$n" >"$QC"
	#directly including all models in the precache.mdl file makes studiomdl crash
	head -n "$PARTITIONSZ" "$LIST" | sed 's:^\(.*\):$includemodel "\1":g' >>"$QC"
	sed "1,${PARTITIONSZ}d" "$LIST" >"$SAVE"; mv "$SAVE" "$LIST"
	#<&2 printf 'QC FILE:\n%s\n' "$(cat "$QC")"
	compile "$QC"
	n=$((n+=1))
done

printf '$modelname "precache.mdl"\n' > "$QC"
while [ "$n" -gt "0" ]; do
	n=$((n-=1))
	printf '$includemodel "precache_%d.mdl"\n' "$n" >>"$QC"
done
#<&2 printf 'MASTER QC FILE:\n%s\n' "$(cat "$QC")"
compile "$QC"
mkdir -p "$MODELSD/models/"
mv "$WINTF2DIR/tf/models/precache"* "$MODELSD/models/"
