workshop rework
This commit is contained in:
1 parent
a3a80dfa16
commit
fb39e290c0
115 files changed
+1865
-497
No files matched your search
@@ -0,0 +1,127 @@
|
||||
"""Plain Python launcher. Does not import unreal; works on Windows and Linux."""
|
||||
import argparse
|
||||
from contextlib import nullcontext
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from progress_display import ProgressDisplay
|
||||
from console_links import file_link
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / "Content/Python"))
|
||||
from ue_workshop.paths import executable
|
||||
|
||||
|
||||
def editor_path(explicit=None):
|
||||
value = explicit or os.environ.get("WORKSHOP_UNREAL") or shutil.which("UnrealEditor")
|
||||
if not value and os.name == "nt":
|
||||
value = r"C:\Program Files\Epic Games\UE_5.7\Engine\Binaries\Win64\UnrealEditor-Cmd.exe"
|
||||
if value and Path(value).is_file():
|
||||
return str(Path(value).resolve())
|
||||
raise FileNotFoundError("Ustaw WORKSHOP_UNREAL na plik UnrealEditor-Cmd.exe / UnrealEditor (UE 5.7).")
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("script", nargs="?", default="exercises/my_shot.py")
|
||||
parser.add_argument("--editor", help="Pelna sciezka do UE 5.7")
|
||||
parser.add_argument("--check", action="store_true", help="Sprawdz srodowisko bez otwierania UE")
|
||||
parser.add_argument("--blender", action="store_true", help="Przy --check wymagaj tez Blendera")
|
||||
parser.add_argument("--timeout", type=int, default=900)
|
||||
parser.add_argument("--render", action="store_true", help="Renderuj zmienna shot ze skryptu, nawet gdy RENDER=False")
|
||||
parser.add_argument("--single-frame", type=int, help="Renderuj tylko wskazana klatke (bez MP4)")
|
||||
parser.add_argument("--verbose", action="store_true", help="Pokazuj pelne logi UE w konsoli")
|
||||
parser.add_argument("--links", choices=("auto", "always", "never"), default="auto",
|
||||
help="Klikalne sciezki w terminalu (domyslnie: auto)")
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
def link(path, stream=None):
|
||||
return file_link(path, args.links, stream)
|
||||
|
||||
editor = editor_path(args.editor)
|
||||
if args.check:
|
||||
print("UE:", editor)
|
||||
print("FFmpeg:", executable("ffmpeg"))
|
||||
if args.blender:
|
||||
print("Blender:", executable("blender"))
|
||||
print("Projekt:", ROOT / "ExampleProject.uproject")
|
||||
return 0
|
||||
script = (ROOT / args.script).resolve()
|
||||
if not script.is_file():
|
||||
raise FileNotFoundError(script)
|
||||
status = ROOT / "Saved/Workshop" / (uuid.uuid4().hex + ".json")
|
||||
log_path = status.with_suffix(".log")
|
||||
progress_path = status.with_suffix(".progress.jsonl")
|
||||
status.parent.mkdir(parents=True, exist_ok=True)
|
||||
env = dict(os.environ, WORKSHOP_SCRIPT=str(script), WORKSHOP_STATUS=str(status), WORKSHOP_BATCH="1")
|
||||
env["WORKSHOP_PROGRESS"] = str(progress_path)
|
||||
env["WORKSHOP_RENDER"] = "1" if args.render else "0"
|
||||
env["WORKSHOP_SINGLE_FRAME"] = "" if args.single_frame is None else str(args.single_frame)
|
||||
command = [editor, str(ROOT / "ExampleProject.uproject"),
|
||||
"-ExecutePythonScript=" + (ROOT / "tools/ue_bootstrap.py").as_posix(),
|
||||
"-RenderOffscreen", "-unattended", "-nosplash", "-nosound", "-stdout",
|
||||
"-FullStdOutLogOutput", "-NoLoadingScreen"]
|
||||
if args.verbose:
|
||||
# UE writes its own log when console output is streamed directly.
|
||||
command.append("-abslog=" + log_path.as_posix())
|
||||
print("Uruchamiam:", script, flush=True)
|
||||
progress = ProgressDisplay(progress_path)
|
||||
try:
|
||||
# Keep native stderr (including third-party plugins) out of the terminal too.
|
||||
with nullcontext(None) if args.verbose else log_path.open("wb") as output:
|
||||
with subprocess.Popen(command, env=env, cwd=ROOT, stdout=output,
|
||||
stderr=subprocess.STDOUT) as process:
|
||||
deadline = time.monotonic() + args.timeout
|
||||
try:
|
||||
while True:
|
||||
progress.update()
|
||||
remaining = deadline - time.monotonic()
|
||||
if remaining <= 0:
|
||||
raise subprocess.TimeoutExpired(command, args.timeout)
|
||||
try:
|
||||
exit_code = process.wait(timeout=min(0.5, remaining))
|
||||
except subprocess.TimeoutExpired:
|
||||
continue
|
||||
progress.update()
|
||||
break
|
||||
finally:
|
||||
if process.poll() is None:
|
||||
process.kill()
|
||||
process.wait()
|
||||
except subprocess.TimeoutExpired:
|
||||
print(f"Przekroczono limit czasu UE. Log: {link(log_path, sys.stderr)}", file=sys.stderr)
|
||||
return 1
|
||||
if not status.is_file():
|
||||
print(f"UE nie zapisalo wyniku (kod {exit_code}). Log: {link(log_path, sys.stderr)}", file=sys.stderr)
|
||||
return 1
|
||||
try:
|
||||
result = json.loads(status.read_text(encoding="utf-8"))
|
||||
except (OSError, ValueError) as exc:
|
||||
print(f"Nie mozna odczytac wyniku: {exc}. Log: {link(log_path, sys.stderr)}", file=sys.stderr)
|
||||
return 1
|
||||
result["editor_exit_code"] = exit_code
|
||||
result["log"] = str(log_path)
|
||||
status.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
success = exit_code == 0 and result.get("success")
|
||||
if success:
|
||||
print("Gotowe:", link(result.get("video") or result.get("output") or script))
|
||||
else:
|
||||
print("Blad:", result.get("error") or f"UE zakonczyl prace z kodem {exit_code}.", file=sys.stderr)
|
||||
print("Log:", link(log_path))
|
||||
if args.verbose:
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
return 0 if success else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
raise SystemExit(main())
|
||||
except (OSError, ValueError) as exc:
|
||||
print(str(exc), file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
Reference in new issue
Block a user