Im trying to create a python script that adds pre-roll to my tracks in Unreal 5.4. Currently it correctly sets the CameraCuts, but fails to correctly update Subsequences and CameraComponents > Spawned + Transform to Pre Roll Frames 0100, instead setting it to 0000* which is odd. I have tried saving and re-opening to see if its a visual bug but it doesn't seem to update and I really need this to reflect the change. here is my script Any help is greatly appreciated! import unreal # ----------------------------- CONFIG --------------------------------- SUBSEQ_PREROLL_FRAMES = 100 CAMERA_PREROLL_FRAMES = 100 CAMERA_CUT_HEAD_EXTEND_FRAMES = SUBSEQ_PREROLL_FRAMES - 12 # 88 frames # ---------------------------------------------------------------------- # ----------------------------- Helpers --------------------------------- def _get_or_open_target_sequence(): seq = unreal.LevelSequenceEditorBlueprintLibrary.get_current_level_sequence() if seq: return seq # Fallback: exactly one selected LevelSequence asset try: selected = unreal.EditorUtilityLibrary.get_selected_assets() except Exception: selected = [] level_sequences = [a for a in selected if isinstance(a, unreal.LevelSequence)] if len(level_sequences) == 1: seq = level_sequences[0] try: unreal.LevelSequenceEditorBlueprintLibrary.open_level_sequence(seq) except Exception: pass return seq return None def _get_sections(track): try: return list(track.get_sections()) except Exception: return [] def _get_section_start_end(section): try: start = int(section.get_start_frame()) end = int(section.get_end_frame()) return start, end except Exception: pass try: rng = section.get_range() start = int(rng.lower_bound.value) end = int(rng.upper_bound.value) return start, end except Exception: return None, None def _set_section_start_end(section, new_start, end): try: section.set_start_frame(int(new_start)) section.set_end_frame(int(end)) return True except Exception: pass try: section.set_range(int(new_start), int(end)) return True except Exception: return False # ----------------------------- Debugging --------------------------------- def debug_tracks(seq): unreal.log(f"=== Debug Tracks for sequence '{seq.get_name()}' ===") try: tracks = unreal.MovieSceneSequenceExtensions.get_tracks(seq) except Exception: tracks = [] unreal.log(f"Master tracks found: {len(tracks)}") for t in tracks: try: sections = t.get_sections() unreal.log(f"Track: {t.get_display_name()} ({t.get_class().get_name()}), sections: {len(sections)}") for sec in sections: start, end = _get_section_start_end(sec) pre_roll = sec.get_pre_roll_frames() if hasattr(sec, "get_pre_roll_frames") else "N/A" unreal.log(f" Section: {sec.get_name()}, start={start}, end={end}, pre_roll={pre_roll}") except Exception as e: unreal.log_warning(f"Error reading track: {str(e)}") # ----------------------------- Main logic --------------------------------- def _process_subsequence_tracks(seq): modified = 0 try: tracks = unreal.MovieSceneSequenceExtensions.get_tracks(seq) except Exception: tracks = [] for t in tracks: if isinstance(t, unreal.MovieSceneSubTrack): for sec in _get_sections(t): start, end = _get_section_start_end(sec) if start is not None and end is not None: try: sec.set_pre_roll_frames(SUBSEQ_PREROLL_FRAMES) modified += 1 unreal.log(f"[PreRoll] Subsequence section '{sec.get_name()}' set to {SUBSEQ_PREROLL_FRAMES}") except Exception as e: unreal.log_warning(f"[PreRoll] Failed to set subsequence section '{sec.get_name()}': {e}") else: unreal.log_warning(f"[PreRoll] Skipping subsequence section '{sec.get_name()}' (invalid start/end)") return modified def _process_camera_tracks(seq): modified = 0 try: bindings = unreal.MovieSceneSequenceExtensions.get_bindings(seq) except Exception: bindings = [] for b in bindings: try: tracks = unreal.MovieSceneBindingExtensions.get_tracks(b) except Exception: tracks = [] for tr in tracks: sections = _get_sections(tr) track_name = tr.get_display_name() if hasattr(tr, "get_display_name") else "UnnamedTrack" track_class = tr.get_class().get_name() if hasattr(tr, "get_class") else "UnknownClass" for sec in sections: try: sec_name = sec.get_name() start, end = _get_section_start_end(sec) pre_roll_before = sec.get_pre_roll_frames() if hasattr(sec, "get_pre_roll_frames") else "N/A" unreal.log(f"[DEBUG] Track '{track_name}' ({track_class}) Section '{sec_name}', start={start}, end={end}, pre_roll={pre_roll_before}") # Determine if we should set pre-roll valid_types_for_preroll = (unreal.MovieSceneSpawnTrack, unreal.MovieScene3DTransformTrack) if isinstance(tr, valid_types_for_preroll): sec.set_pre_roll_frames(CAMERA_PREROLL_FRAMES) modified += 1 unreal.log(f"[PreRoll] Camera section '{sec_name}' set to {CAMERA_PREROLL_FRAMES}") else: # Only skip tracks that are not supported (e.g., Material, Visibility, Float) if start is None or end is None: unreal.log_warning(f"[PreRoll] Skipping unsupported section '{sec_name}'") except Exception as e: unreal.log_warning(f"[PreRoll] Failed to process camera section '{sec_name}': {e}") return modified def _process_camera_cuts(seq): modified = 0 try: tracks = unreal.MovieSceneSequenceExtensions.get_tracks(seq) except Exception: tracks = [] for t in tracks: if not isinstance(t, unreal.MovieSceneCameraCutTrack): continue sections = _get_sections(t) if not sections: continue sec = sections[0] # only first CameraCut try: start, end = _get_section_start_end(sec) if start is None or end is None: continue current_marker = sec.get_pre_roll_frames() or 0 if current_marker >= CAMERA_CUT_HEAD_EXTEND_FRAMES: continue delta = CAMERA_CUT_HEAD_EXTEND_FRAMES - current_marker new_start = start - int(delta) if _set_section_start_end(sec, new_start, end): sec.set_pre_roll_frames(CAMERA_CUT_HEAD_EXTEND_FRAMES) modified += 1 unreal.log(f"[PreRoll] CameraCut '{sec.get_name()}' start moved from {start} to {new_start}") except Exception as e: unreal.log_warning(f"[PreRoll] Failed to process CameraCut '{sec.get_name()}': {e}") return modified def add_preroll_to_sequence_safely(): seq = _get_or_open_target_sequence() if not seq: unreal.log_error("[PreRoll] No Level Sequence active or selected. Open one or select exactly one LevelSequence asset.") return False unreal.log("=== DEBUG BEFORE MODIFICATION ===") debug_tracks(seq) total_modified = 0 with unreal.ScopedEditorTransaction("Add Sequencer Pre-roll (All Sections)"): total_modified += _process_subsequence_tracks(seq) total_modified += _process_camera_tracks(seq) total_modified += _process_camera_cuts(seq) try: unreal.EditorAssetLibrary.save_asset(seq.get_path_name()) except Exception: pass if total_modified > 0: unreal.log(f"[PreRoll] Applied pre-roll updates to '{seq.get_name()}'. Sections modified: {total_modified}") else: unreal.log(f"[PreRoll] '{seq.get_name()}' already compliant. No changes applied.") unreal.log("=== DEBUG AFTER MODIFICATION ===") debug_tracks(seq) return True # ----------------------------- RUN ------------------------------------ add_preroll_to_sequence_safely() Continue reading...