#!/usr/bin/env bash # Builds the world map: renders the art from the planet images, then imports it and writes the definition asset. # # Scripts/Authoring/build_world_map.sh # render the art and import it # Scripts/Authoring/build_world_map.sh --art-only # render the PNGs, import nothing (no editor needed) # Scripts/Authoring/build_world_map.sh --dry-run # say what would be imported, change nothing # # Two stages because they need two languages. Rendering reads 33-megapixel RGB PNGs, which the engine's Python # cannot decode at any useful speed (heightmap_io.py is greyscale-only and unfilters a byte at a time), so it is # a Go tool: Tools/MapArt, a few seconds for the lot. Importing has to happen inside the editor, so it is # Python. The contract between them is RawContent/World/MapArt/, which holds both the manifest and the rendered # PNGs. # # Unlike build_region.sh this touches no level and needs no batching: it writes four textures and one data # asset. It does check for a lock, though, for the same reason - an editor holding those assets open would make # the import look like it worked and change nothing on disk. # # The script's own arguments go *inside* the quoted -script= value. Anything after it is eaten by the engine # and never reaches Python. set -u ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" UE_ROOT="${UE_ROOT:-D:/UE_5.8}" CMD="$UE_ROOT/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" PYTHON="$UE_ROOT/Engine/Binaries/ThirdParty/Python3/Win64/python.exe" PROJECT="$ROOT/Salty.uproject" SCRIPT="$ROOT/Scripts/Authoring/create_world_map.py" LOG="$ROOT/Saved/Logs/world_map.log" art_only=0 script_args="" case "${1:-}" in --art-only) art_only=1 ;; --dry-run) script_args=" --dry-run" ;; "") ;; *) echo "usage: $(basename "$0") [--art-only|--dry-run]" >&2; exit 2 ;; esac echo "=== rendering the map art" if ! (cd "$ROOT/Tools/MapArt" && go run . build); then echo "Tools/MapArt failed; nothing imported." >&2 exit 1 fi echo "=== checking the art is of the world L_World was cut from" # Advisory, not a gate: a layer of ice or cloud legitimately scores lower, and only a person can tell that from # a layer of the wrong planet. A number in the eighties or above is ordinary; one in the fifties is not. (cd "$ROOT/Tools/MapArt" && go run . check) || true if [ "$art_only" -eq 1 ]; then echo "done: art only, nothing imported" exit 0 fi # An editor with these assets loaded holds their files. The import would appear to succeed and save nothing. for name in DA_WorldMap_L_World T_WorldMap_Relief T_WorldMap_Colour T_WorldMap_Satellite T_WorldMap_Climate; do file="$ROOT/Content/World/Maps/$name.uasset" if [ -f "$file" ] && [ -x "$PYTHON" ]; then if ! "$PYTHON" -c "import sys; open(sys.argv[1], 'r+b').close()" "$file" 2>/dev/null; then echo "$file is locked: an editor has it open." >&2 echo "Close the editor and run this again." >&2 exit 1 fi fi done mkdir -p "$ROOT/Saved/Logs" echo "=== importing" "$CMD" "$PROJECT" -run=pythonscript \ -script="$SCRIPT$script_args" \ -unattended -nopause -abslog="$LOG" >/dev/null 2>&1 # Not the exit code: UnrealEditor-Cmd returns non-zero whenever anything logged an Error, and this project logs # several on every start. The line the script prints on success is the honest signal. if grep -q "world map saved:" "$LOG" 2>/dev/null; then grep -E "LogPython: (world map| )" "$LOG" | sed 's/.*LogPython: //' echo "done" exit 0 fi if [ -n "$script_args" ] && grep -q "dry run: nothing written" "$LOG" 2>/dev/null; then grep -E "LogPython: " "$LOG" | sed 's/.*LogPython: //' exit 0 fi echo "the import did not report success; see $LOG" >&2 grep -E "LogPython: Error|Python script executed with errors|Traceback|RuntimeError" "$LOG" 2>/dev/null | tail -10 >&2 exit 1