Files
dotcom-arcade/streaming/streamer/root/usr/local/bin/fp-launch
T
branderson e531228fa9 fix(streaming): keep Flash Player's window in place while it's open
Flash Player moves its window back to the top of the screen once the
movie has loaded, bringing the menu bar back. The streamer now checks
the window twice a second and puts it back, logging the first few
times.
2026-10-14 18:10:11 -07:00

90 lines
4.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# Launch a Flashpoint game by ID the way the Linux launcher does: start the
# game server, mount the game's zip, then run its application through the proxy.
set -euo pipefail
FP_PATH=${FP_PATH:-/flashpoint}
ID=${1:?usage: fp-launch <game id>}
DB=$FP_PATH/Data/flashpoint.sqlite
API=http://127.0.0.1:22501/fpProxy/api
[[ $ID =~ ^[0-9a-f-]{36}$ ]] || { echo "Invalid game id: $ID" >&2; exit 1; }
if ! curl -s -o /dev/null "$API/listmountzip"; then
"$FP_PATH/Server/FlashpointGameServer" -rootPath "$FP_PATH" \
-useInfinityServer=false -handleLegacyRequests=true &
until curl -s -o /dev/null "$API/listmountzip"; do sleep 0.2; done
fi
IFS=$'\x1f' read -r app cmd date_added < <(sqlite3 -readonly -separator $'\x1f' "$DB" "
select coalesce(nullif(d.applicationPath, ''), g.applicationPath),
coalesce(nullif(d.launchCommand, ''), g.launchCommand),
coalesce(d.dateAdded, '')
from game g left join game_data d on d.id = g.activeDataId
where g.id = '$ID'") || true
[[ -n ${app:-} ]] || { echo "Game not found: $ID" >&2; exit 1; }
if [[ -n $date_added ]]; then
zip=$FP_PATH/Data/Games/$ID-$(date -u -d "$date_added" +%s%3N).zip
curl -sf -X POST -H 'Content-Type: application/json' \
-d "{\"filePath\": \"$zip\"}" "$API/mountzip" >/dev/null ||
{ echo "Failed to mount $zip" >&2; exit 1; }
fi
echo "Launching $ID: $app $cmd"
case ${app,,} in
'fpsoftware\startjava.bat' | 'fpsoftware\startjavainbrowser.bat')
# Supplies the browser's JavaScript bridge, a browser-like network policy,
# and a window holding only the applet
export JAVA_TOOL_OPTIONS="-javaagent:/opt/flashpoint/applet-support.jar -Djava.security.policy=/opt/flashpoint/applet.policy"
FP_PATH=$FP_PATH exec "$FP_PATH/FPSoftware/startJava.sh" "$cmd" ;;
*)
mapfile -d '' argv < <(FP_PATH=$FP_PATH FP_WRITABLE=$HOME/flashpoint fp-command "$app" "$cmd") || true
(( ${#argv[@]} > 1 )) || { echo "Unsupported application: $app" >&2; exit 1; }
export FP_PATH HTTP_PROXY=http://127.0.0.1:22500/ http_proxy=http://127.0.0.1:22500/
export PATH=$FP_PATH/FPSoftware/Wine/bin:$PATH WINEDEBUG=-all WINEDLLOVERRIDES='mscoree,mshtml='
# Flash Player keeps saves (SharedObjects) here
mkdir -p "$HOME/saves/Flash_Player" "$HOME/.macromedia"
[[ -e $HOME/.macromedia/Flash_Player ]] || ln -s "$HOME/saves/Flash_Player" "$HOME/.macromedia/Flash_Player"
if [[ ${app,,} == 'fpsoftware\flash\'* ]]; then
# Hide the projector's menu bar by moving it above the display, and fill
# the display with the movie. Not full screen, which some games, such as
# Bloons, don't play right in. The window manager keeps windows on
# screen, so the window is taken out of its hands first.
(
set +eo pipefail
wid=$(xdotool search --sync --onlyvisible --name 'Flash Player' | head -1)
read -r width height < <(xdotool getdisplaygeometry)
# GTK draws the menu bar in the window itself, and the movie in the
# largest child window, below it: the movie's offset is the menu bar's height
menu=$(xwininfo -children -id "$wid" | awk '
match($0, /[0-9]+x[0-9]+\+-?[0-9]+\+-?[0-9]+/) {
split(substr($0, RSTART, RLENGTH), g, /[x+]/)
if (g[1] * g[2] > area) { area = g[1] * g[2]; top = g[4] }
}
END { print top + 0 }')
((menu >= 0 && menu < height)) || menu=0
echo "Flash Player window $wid: menu bar ${menu}px, display ${width}x${height}"
xdotool windowunmap --sync "$wid"
xdotool set_window --overrideredirect 1 "$wid"
xdotool windowmap --sync "$wid"
place() { xdotool windowsize "$wid" "$width" $((height + menu)) windowmove "$wid" 0 $((-menu)); }
place
xdotool windowfocus "$wid"
# Flash Player moves its window back once the movie has loaded, so it's
# kept in place for as long as it's open
moves=0
while geometry=$(xdotool getwindowgeometry --shell "$wid" 2>/dev/null); do
eval "$geometry"
if ((X != 0 || Y != -menu || WIDTH != width || HEIGHT != height + menu)); then
((++moves <= 3)) && echo "Flash Player window moved to $X,$Y (${WIDTH}x${HEIGHT}); putting it back"
place
fi
sleep 0.5
done
) &
fi
cd "${argv[0]}"
exec "${argv[@]:1}" ;;
esac