One directory with sixty scripts stopped being navigable, and the grouping is also the sandbox boundary:
Tools/unreal/ commandlets and the two map builders, with ue_common.py and ue_placement.py as the
shared imports (they need the engine)
Tools/blender/ builders, exporters, the FBX preset, the MPFB character pipeline, blender_screenshots
(they need the Blender Flatpak)
Tools/review/ the visual loop: render_screenshots.sh, judge_screenshot.py, hero_compare.py,
build_comparison_md.py, e2e_asset_check.py, hero_iterate.sh, visual_loop.py,
visual_targets.json
Tools/gen/ image and texture generation: the ComfyUI driver, deterministic texture writers,
reference fetching
Tools/input/ OS-level input injection
root _common.py, check-lfs.sh, addon_compat_probe.py, sibling_asset_audit.py, tests/
Every moved script now resolves the repository root as ../.. and puts the tools root plus its siblings on
sys.path, so 'import ue_common' still works from unreal/. The test suite bootstrap does the same for the five
folders. render_screenshots.sh takes the folder as a third argument to run_cmdlet, and the e2e driver,
hero_iterate.sh and the comparison generator were repointed.
51 README rows now link to their new location, the README gains a Layout section naming each folder's
sandbox, and the architecture notes and Blender README follow the moves.
Verified: 108 tests pass, prettier is clean, judge_screenshot.py and hero_compare.py run from their new
homes, and the e2e run was aborted mid-way (it had been rebuilding an empty DemoMap for 15 minutes) and is
being rerun against the new layout.
87 lines
3.2 KiB
Python
87 lines
3.2 KiB
Python
"""Rebuild both Unreal maps from an empty level, deleting whatever was there before.
|
|
|
|
<engine>/UnrealEditor-Cmd <uproject> -run=pythonscript \
|
|
-script=<repo>/Tools/unreal/ue_recreate_maps.py -nullrhi -unattended -nopause -stdout
|
|
|
|
Why: `Tools/unreal/ue_build_demo_map.py` and `Tools/unreal/ue_build_review_map.py` load the existing map and destroy the
|
|
actors they know about. Anything else that accumulated - an actor from an experiment, a material override, a
|
|
stale world setting - survives every rebuild, which is how a stale road mesh and a duplicated vehicle actor
|
|
both got saved back into the map. Deleting the `.umap` and creating an empty level makes every run start from
|
|
the same place.
|
|
|
|
The umap files are LFS-tracked and check out read-only, so chmod comes first; and a level cannot be deleted
|
|
while it is the one the editor has open, so a scratch level is created to release it.
|
|
|
|
Result: /tmp/gigline/recreate-maps.txt
|
|
"""
|
|
|
|
import os
|
|
|
|
import unreal
|
|
|
|
MAPS = ("/Game/Hollywood/DemoMap", "/Game/Test/ReviewMap")
|
|
SCRATCH = "/Game/Test/_RecreateScratch"
|
|
RESULT = "/tmp/gigline/recreate-maps.txt"
|
|
lines = []
|
|
|
|
|
|
def log(message):
|
|
lines.append(str(message))
|
|
unreal.log(str(message))
|
|
|
|
|
|
def make_writable(path):
|
|
"""A .umap under Content/ that is read-only cannot be deleted; LFS checks it out that way."""
|
|
disk = os.path.join(unreal.Paths.project_content_dir(),
|
|
path.replace("/Game/", "") + ".umap")
|
|
try:
|
|
mode = os.stat(disk).st_mode & 0o777
|
|
if not mode & 0o200:
|
|
os.chmod(disk, 0o644)
|
|
log(f"{path}: chmod u+w ({oct(mode)} -> 0o644)")
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
|
|
def main():
|
|
les = unreal.get_editor_subsystem(unreal.LevelEditorSubsystem)
|
|
scratch_made = False
|
|
for path in MAPS:
|
|
make_writable(path)
|
|
current = unreal.EditorLevelLibrary.get_editor_world()
|
|
current_path = current.get_path_name().split(".")[0] if current else ""
|
|
if path == current_path:
|
|
# The editor cannot delete the map it has open: park it on a scratch level first.
|
|
if not scratch_made:
|
|
les.new_level(SCRATCH)
|
|
scratch_made = True
|
|
else:
|
|
les.load_level(SCRATCH)
|
|
log(f"{path}: released by switching to {SCRATCH}")
|
|
if unreal.EditorAssetLibrary.does_asset_exist(path):
|
|
if unreal.EditorAssetLibrary.delete_asset(path):
|
|
log(f"{path}: deleted")
|
|
else:
|
|
log(f"{path}: could not delete")
|
|
if les.new_level(path):
|
|
log(f"{path}: created empty")
|
|
else:
|
|
log(f"{path}: FAILED to create")
|
|
if unreal.EditorAssetLibrary.does_asset_exist(SCRATCH):
|
|
unreal.EditorAssetLibrary.delete_asset(SCRATCH)
|
|
ok = all(f"{path}: created empty" in line for path in MAPS for line in lines)
|
|
lines.append(f"VERDICT: {'PASS' if ok else 'FAIL'}")
|
|
log(f"recreate {'ok' if ok else 'FAILED'}")
|
|
|
|
|
|
try:
|
|
main()
|
|
except Exception as exc: # noqa: BLE001
|
|
import traceback
|
|
log(f"FAILED: {type(exc).__name__}: {exc}")
|
|
log(traceback.format_exc())
|
|
lines.append("VERDICT: FAIL")
|
|
|
|
with open(RESULT, "w") as handle:
|
|
handle.write("\n".join(lines) + "\n")
|