From 7fd194d98bdcb171fd04d62d26bde1c07db2fbc8 Mon Sep 17 00:00:00 2001 From: Jennifer Taylor Date: Mon, 24 May 2021 18:35:43 +0000 Subject: [PATCH] Hack/fix for SWFs with orphaned tags, I think this is correct? --- bemani/format/afp/render.py | 27 ++++++++++++++++++++++++--- bemani/format/afp/swf.py | 10 +++++----- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/bemani/format/afp/render.py b/bemani/format/afp/render.py index 9cd7598..1a2850a 100644 --- a/bemani/format/afp/render.py +++ b/bemani/format/afp/render.py @@ -124,6 +124,7 @@ class PlacedClip(PlacedObject): super().__init__(object_id, depth, rotation_offset, transform, mult_color, add_color, blend, mask) self.placed_objects: List[PlacedObject] = [] self.frame: int = 0 + self.unplayed_tags: List[int] = [i for i in range(len(source.tags))] self.__source = source # Dynamic properties that are adjustable by SWF bytecode. @@ -138,6 +139,11 @@ class PlacedClip(PlacedObject): if self.frame < len(self.source.frames): self.frame += 1 + def rewind(self) -> None: + self.frame = 0 + self.unplayed_tags = [i for i in range(len(self.__source.tags))] + self.placed_objects = [] + @property def finished(self) -> bool: return self.frame == len(self.source.frames) @@ -954,8 +960,7 @@ class AFPRenderer(VerboseOutput): # during some bytecode update in this loop. if clip.frame > clip.requested_frame: # Rewind this clip to the beginning so we can replay until the requested frame. - clip.placed_objects = [] - clip.frame = 0 + clip.rewind() self.vprint(f"{prefix} Processing frame {clip.frame} on our way to frame {clip.requested_frame}") @@ -965,8 +970,24 @@ class AFPRenderer(VerboseOutput): # Execute each tag in the frame if we need to move forward to a new frame. if clip.frame != clip.requested_frame: frame = clip.source.frames[clip.frame] - tags = clip.source.tags[frame.start_tag_offset:(frame.start_tag_offset + frame.num_tags)] + orphans: List[Tag] = [] + played_tags: Set[int] = set() + # See if we have any orphans that need to be placed before this frame will work. + for unplayed_tag in clip.unplayed_tags: + if unplayed_tag < frame.start_tag_offset: + self.vprint(f"{prefix} Including orphaned tag {unplayed_tag} in frame evaluation") + played_tags.add(unplayed_tag) + orphans.append(clip.source.tags[unplayed_tag]) + + for tagno in range(frame.start_tag_offset, frame.start_tag_offset + frame.num_tags): + played_tags.add(tagno) + + # Check these off our future todo list. + clip.unplayed_tags = [t for t in clip.unplayed_tags if t not in played_tags] + + # Grab the normal list of tags, add to the orphans. + tags = orphans + clip.source.tags[frame.start_tag_offset:(frame.start_tag_offset + frame.num_tags)] for tagno, tag in enumerate(tags): # Perform the action of this tag. self.vprint(f"{prefix} Sprite Tag ID: {clip.source.tag_id}, Current Tag: {frame.start_tag_offset + tagno}, Num Tags: {frame.num_tags}") diff --git a/bemani/format/afp/swf.py b/bemani/format/afp/swf.py index 3a4f91c..9076ca4 100644 --- a/bemani/format/afp/swf.py +++ b/bemani/format/afp/swf.py @@ -956,7 +956,7 @@ class SWF(TrackedCoverage, VerboseOutput): size: int, dataoffset: int, tag_parent_sprite: Optional[int], - tag_frame: int, + tag_frame: str, prefix: str = "", ) -> Tag: if tagid == AP2Tag.AP2_SHAPE: @@ -1021,7 +1021,7 @@ class SWF(TrackedCoverage, VerboseOutput): return AP2DefineFontTag(font_id, fontname, xml_prefix, heights, text_indexes) elif tagid == AP2Tag.AP2_DO_ACTION: datachunk = ap2data[dataoffset:(dataoffset + size)] - bytecode = self.__parse_bytecode(f"on_enter_{f'sprite_{tag_parent_sprite}' if tag_parent_sprite is not None else 'main'}_frame_{tag_frame}", datachunk, prefix=prefix) + bytecode = self.__parse_bytecode(f"on_enter_{f'sprite_{tag_parent_sprite}' if tag_parent_sprite is not None else 'main'}_{tag_frame}", datachunk, prefix=prefix) self.add_coverage(dataoffset, size) return AP2DoActionTag(bytecode) @@ -1941,7 +1941,7 @@ class SWF(TrackedCoverage, VerboseOutput): # First, parse frames. frames: List[Frame] = [] - tag_to_frame: Dict[int, int] = {} + tag_to_frame: Dict[int, str] = {} self.vprint(f"{prefix}Number of Frames: {frame_count}") for i in range(frame_count): frame_info = struct.unpack("