#!/usr/bin/env bash set -euo pipefail repo_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" output_dir="$repo_dir/Builds/linux" player="$output_dir/Simulation.x86_64" mode="${1:---demo}" case "$mode" in --demo|--server|--vnc) ;; *) echo "Usage: $0 [--demo | --server | --vnc]"; exit 2 ;; esac if [[ ! -x "$player" ]]; then echo "Build the Linux player first: ./build-linux.sh" >&2 exit 1 fi if [[ "$mode" == --vnc && -z "${DISPLAY:-}" ]]; then exec xvfb-run -a -s '-screen 0 1280x800x24 -nolisten tcp' "$0" --vnc fi if [[ "$mode" == --demo && -z "${DISPLAY:-}" ]]; then echo "No display. Use --vnc to view over SSH, or --server for a headless server." >&2 exit 1 fi if [[ "$mode" == --vnc ]]; then command -v x11vnc >/dev/null || { echo "Install x11vnc, xvfb, and xauth." >&2; exit 1; } fi cd "$repo_dir" mkdir -p "$output_dir" children=() cleanup() { trap - EXIT INT TERM if (( ${#children[@]} )); then kill "${children[@]}" 2>/dev/null || true wait "${children[@]}" 2>/dev/null || true fi } trap cleanup EXIT trap 'exit 130' INT trap 'exit 143' TERM # These services control the local simulation. Refuse to reuse unknown servers. python3 - <<'PY' import socket for port in (8080, 8081): with socket.socket() as sock: sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: sock.bind(('127.0.0.1', port)) except OSError: raise SystemExit('Port %s is already in use; stop the previous simulation first.' % port) with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock: try: sock.bind(('0.0.0.0', 7777)) except OSError: raise SystemExit('UDP port 7777 is already in use.') PY SIMULATION_BIND_ADDRESS=127.0.0.1 python3 -u traffic_light_server.py >"$output_dir/traffic.log" 2>&1 & children+=("$!") SIMULATION_BIND_ADDRESS=127.0.0.1 python3 -u event_server.py >"$output_dir/events.log" 2>&1 & children+=("$!") python3 - <<'PY' import time, urllib.request for port, path in ((8080, '/trafficLights/'), (8081, '/tweetCount')): for attempt in range(50): try: with urllib.request.urlopen('http://127.0.0.1:%s%s' % (port, path), timeout=1) as response: response.read() break except OSError: time.sleep(.1) else: raise SystemExit('Backend failed to start; inspect Builds/linux/*.log') PY : > "$output_dir/server.log" "$player" -batchmode -nographics --server \ --traffic-url http://127.0.0.1:8080 --event-url http://127.0.0.1:8081 \ -logFile "$output_dir/server.log" >"$output_dir/server-console.log" 2>&1 & children+=("$!") echo "Simulation server running on port 7777. Logs: $output_dir" if [[ "$mode" != --server ]]; then # Wait for UNet to finish loading the scene before connecting the client. for ((attempt=0; attempt<100; attempt++)); do if grep -q 'Simulation server started' "$output_dir/server.log"; then break; fi kill -0 "${children[2]}" 2>/dev/null || exit 1 sleep .1 done if ! grep -q 'Simulation server started' "$output_dir/server.log"; then echo "Server startup timed out; inspect $output_dir/server.log" >&2 exit 1 fi "$player" --connect 127.0.0.1 -screen-width 1280 -screen-height 800 \ -screen-fullscreen 0 -force-glcore -logFile "$output_dir/client.log" \ >"$output_dir/client-console.log" 2>&1 & children+=("$!") fi if [[ "$mode" == --vnc ]]; then x11vnc -display "$DISPLAY" -localhost -rfbport 5901 -forever -shared -nopw \ >"$output_dir/vnc.log" 2>&1 & children+=("$!") echo "Forward SSH port 5901, then connect your VNC viewer to localhost:5901." fi echo "Press Ctrl-C to stop the simulation and its services." wait -n "${children[@]}"