OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scripts / dev-editor.sh

140 lines · bash ref:
#!/usr/bin/env bash
# dev-editor — open the SOURCE TREE in the Godot editor.
#
#   scripts/dev-editor.sh                                  # open the project
#   scripts/dev-editor.sh scenes/test/proc_bridge_test.tscn # open one scene
#   scripts/dev-editor.sh res://scenes/game/game.tscn
#   scripts/dev-editor.sh <scene> -- --verbose             # extra godot args
#   scripts/dev-editor.sh --no-daemon                      # no keet-daemon
#
# WHY THIS EXISTS, and why it is NOT dev-run.sh. dev-run.sh RUNS the game (plus
# keet-daemon, which the game cannot do without). This opens the EDITOR, which
# is a different thing and is required for any @tool scene -- every path in
# scenes/test/proc_bridge_test.gd sits behind Engine.is_editor_hint(), so
# running the project executes none of it and the Blender bridge never starts.
#
# THE keet-daemon IS STARTED (or reused) HERE TOO, since 2026-10-05. It used to be
# skipped on the grounds that editor autoloads do not run -- true of the editor,
# but F5 RUNS THE GAME from it, and the game with no daemon keeps every durable
# write in memory and loses it on quit. Home is a keet room (docs/home-world-
# design.md), so the daemon always runs. Only a daemon started here is stopped
# on exit; --no-daemon skips it. Same code as dev-run.sh: scripts/daemon.sh.
#
# THE ENGINE IS THE FORK, NOT SYSTEM godot4 (4.6.stable) -- same binary as
# dev-run.sh, because both source scripts/engine.sh.
#
# FIRST LAUNCH AFTER A CLEAN CHECKOUT reimports the whole project and can sit on
# "Scanning file structure..." for minutes with no window. That is not a hang.
# Output is passed straight through so you can watch it happen.
#
# THE EDITOR REWRITES project.godot ON EXIT, and it does not round-trip: it
# strips every comment and reorders keys. Opening the editor once silently
# deleted the 30-line block documenting the Jolt swap. Nothing warned.
#
# Warning is not enough, because losing that block is not acceptable and a
# warning still leaves you to clean up. So this compares the SETTINGS -- the
# key=value pairs, ignoring comments, blank lines and order -- before and after:
#
#   settings identical  -> your file is restored verbatim, comments intact.
#                          The rewrite carried no information, so nothing is lost
#                          by discarding it.
#   settings changed    -> the editor's file is KEPT, because you meant that,
#                          and the changed keys are printed along with the
#                          pre-launch copy so you can put the comments back.

set -uo pipefail

REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
. "$REPO/scripts/engine.sh"
DAEMON_TAG=dev-editor
. "$REPO/scripts/daemon.sh"
# NVIDIA's shader disk cache defaults to a 128 MB cap and stores nothing new once
# full; every launch then recompiles proc-nodes' and dc-terrain's ~115k-char
# shaders in the driver (6.8-7.3 s each, measured). See index.js.
export __GL_SHADER_DISK_CACHE_SIZE="${__GL_SHADER_DISK_CACHE_SIZE:-4294967296}"

_die() { echo "dev-editor: $*" >&2; exit 1; }

[ -x "$GODOT" ] || _die "engine missing at $GODOT (set HYPER_TPS_GODOT)"
[ -f "$REPO/project.godot" ] || _die "no project.godot in $REPO"

scene=""
godot_args=()
seen_sep=0
want_daemon=1
for a in "$@"; do
  if [ "$seen_sep" = 1 ]; then godot_args+=("$a"); continue; fi
  case "$a" in
    --) seen_sep=1 ;;
    -h|--help) sed -n '2,30p' "${BASH_SOURCE[0]}"; exit 0 ;;
    --no-daemon) want_daemon=0 ;;
    -*) godot_args+=("$a") ;;
    *)  [ -z "$scene" ] || _die "more than one scene given: '$scene' and '$a'"
        scene="$a" ;;
  esac
done

# Normalise a scene argument to res://. Godot resolves a bare relative path
# against its own cwd, not --path, so passing "scenes/foo.tscn" from anywhere
# but the repo root silently opens nothing.
if [ -n "$scene" ]; then
  case "$scene" in
    res://*) rel="${scene#res://}" ;;
    /*)      case "$scene" in
               "$REPO"/*) rel="${scene#"$REPO"/}" ;;
               *) _die "scene is outside the project: $scene" ;;
             esac ;;
    *)       rel="$scene" ;;
  esac
  [ -f "$REPO/$rel" ] || _die "no such scene: $REPO/$rel"
  scene="res://$rel"
fi

# A dangling GDExtension symlink does not fail loudly -- the class simply does
# not register, and the first symptom is a scene that will not instantiate. One
# of these was broken for months, so it is worth the two lines.
for so in "$REPO"/bin/linux/*.so; do
  [ -e "$so" ] || echo "dev-editor: WARNING broken symlink: $so" >&2
done

if [ "$want_daemon" = 1 ]; then
  [ -x "$BARE" ] || _die "bare missing (set HYPER_TPS_BARE), or pass --no-daemon"
  ensure_daemon
  # EXIT covers the normal end (`exit $rc` below) and a Ctrl-C alike.
  trap stop_daemon_if_started EXIT
fi

SNAP="$(mktemp -t project.godot.pre-editor.XXXXXX)"
cp "$REPO/project.godot" "$SNAP"

echo "dev-editor: $(basename "$GODOT") -e ${scene:-<project>} --path $REPO"
DISPLAY="${DISPLAY:-:0}" "$GODOT" --path "$REPO" -e ${scene:+"$scene"} \
  --rendering-driver vulkan "${godot_args[@]+"${godot_args[@]}"}"
rc=$?

if cmp -s "$SNAP" "$REPO/project.godot"; then
  rm -f "$SNAP"
else
  # Compare settings only: strip comments and blanks, keep section headers so a
  # key is qualified by its section, and sort so reordering does not count.
  _settings() {
    sed -e 's/[[:space:]]*$//' -e '/^;/d' -e '/^[[:space:]]*$/d' "$1" | sort
  }
  if diff -q <(_settings "$SNAP") <(_settings "$REPO/project.godot") >/dev/null; then
    cp "$SNAP" "$REPO/project.godot"
    rm -f "$SNAP"
    echo "" >&2
    echo "dev-editor: the editor rewrote project.godot but changed no setting —" >&2
    echo "  it only stripped comments and reordered keys. Your file is restored." >&2
  else
    echo "" >&2
    echo "dev-editor: the editor CHANGED project.godot settings. Keeping its version." >&2
    diff <(_settings "$SNAP") <(_settings "$REPO/project.godot") \
      | grep -E '^[<>]' | sed 's/^/    /' >&2
    echo "  Comments were stripped in the rewrite. Pre-launch copy: $SNAP" >&2
    echo "  Diff: git -C '$REPO' diff project.godot" >&2
  fi
fi

exit $rc