From a6e3ec524ae6f881fa429588376a11e680454d18 Mon Sep 17 00:00:00 2001 From: Jennifer Taylor Date: Mon, 20 Sep 2021 01:16:40 +0000 Subject: [PATCH] Add debugging components options to AFP parser and renderer. --- bemani/format/afp/render.py | 52 +++--- bemani/format/afp/swf.py | 349 ++++++++++++++++++------------------ bemani/format/afp/util.py | 11 +- 3 files changed, 210 insertions(+), 202 deletions(-) diff --git a/bemani/format/afp/render.py b/bemani/format/afp/render.py index 4cd4900..c3b3288 100644 --- a/bemani/format/afp/render.py +++ b/bemani/format/afp/render.py @@ -601,14 +601,14 @@ class AFPRenderer(VerboseOutput): } registers: List[Any] = [UNDEFINED] * 256 - self.vprint(f"{prefix}Bytecode engine starting.") + self.vprint(f"{prefix}Bytecode engine starting.", component="bytecode") while location < len(bytecode.actions): action = bytecode.actions[location] if action.opcode == AP2Action.END: # End the execution. - self.vprint(f"{prefix} Ending bytecode execution.") + self.vprint(f"{prefix} Ending bytecode execution.", component="bytecode") break elif action.opcode == AP2Action.GET_VARIABLE: varname = stack.pop() @@ -627,7 +627,7 @@ class AFPRenderer(VerboseOutput): if not hasattr(obj, attribute): print(f"WARNING: Tried to set attribute {attribute} on {obj} but that attribute doesn't exist!") else: - self.vprint(f"{prefix} Setting attribute {attribute} on {obj} to {set_value}") + self.vprint(f"{prefix} Setting attribute {attribute} on {obj} to {set_value}", component="bytecode") setattr(obj, attribute, set_value) elif action.opcode == AP2Action.CALL_METHOD: # Grab the method name. @@ -646,7 +646,7 @@ class AFPRenderer(VerboseOutput): # Look up the python function we're calling. try: - self.vprint(f"{prefix} Calling method {methname}({', '.join(repr(s) for s in params)}) on {obj}") + self.vprint(f"{prefix} Calling method {methname}({', '.join(repr(s) for s in params)}) on {obj}", component="bytecode") meth = getattr(obj, methname) # Call it, set the return on the stack. @@ -669,7 +669,7 @@ class AFPRenderer(VerboseOutput): # Look up the python function we're calling. try: - self.vprint(f"{prefix} Calling global function {funcname}({', '.join(repr(s) for s in params)})") + self.vprint(f"{prefix} Calling global function {funcname}({', '.join(repr(s) for s in params)})", component="bytecode") func = getattr(globalobj, funcname) # Call it, set the return on the stack. @@ -720,13 +720,13 @@ class AFPRenderer(VerboseOutput): # Next opcode! location += 1 - self.vprint(f"{prefix}Bytecode engine finished.") + self.vprint(f"{prefix}Bytecode engine finished.", component="bytecode") def __place(self, tag: Tag, operating_clip: PlacedClip, prefix: str = "") -> Tuple[Optional[PlacedClip], bool]: # "Place" a tag on the screen. Most of the time, this means performing the action of the tag, # such as defining a shape (registering it with our shape list) or adding/removing an object. if isinstance(tag, AP2ShapeTag): - self.vprint(f"{prefix} Loading {tag.reference} into object slot {tag.id}") + self.vprint(f"{prefix} Loading {tag.reference} into object slot {tag.id}", component="tags") if tag.reference not in self.shapes: raise Exception(f"Cannot find shape reference {tag.reference}!") @@ -743,7 +743,7 @@ class AFPRenderer(VerboseOutput): return None, False elif isinstance(tag, AP2ImageTag): - self.vprint(f"{prefix} Loading {tag.reference} into object slot {tag.id}") + self.vprint(f"{prefix} Loading {tag.reference} into object slot {tag.id}", component="tags") if tag.reference not in self.textures: raise Exception(f"Cannot find texture reference {tag.reference}!") @@ -757,7 +757,7 @@ class AFPRenderer(VerboseOutput): return None, False elif isinstance(tag, AP2DefineSpriteTag): - self.vprint(f"{prefix} Loading Sprite into object slot {tag.id}") + self.vprint(f"{prefix} Loading Sprite into object slot {tag.id}", component="tags") # Register a new clip that we might reference to execute. self.__registered_objects[tag.id] = RegisteredClip(tag.id, tag.frames, tag.tags, tag.labels) @@ -786,7 +786,7 @@ class AFPRenderer(VerboseOutput): if tag.source_tag_id is not None and tag.source_tag_id != obj.source.tag_id: # This completely updates the pointed-at object. - self.vprint(f"{prefix} Replacing Object source {obj.source.tag_id} with {tag.source_tag_id} on object with Object ID {tag.object_id} onto Depth {tag.depth}") + self.vprint(f"{prefix} Replacing Object source {obj.source.tag_id} with {tag.source_tag_id} on object with Object ID {tag.object_id} onto Depth {tag.depth}", component="tags") newobj = self.__registered_objects[tag.source_tag_id] if isinstance(newobj, RegisteredShape): @@ -858,7 +858,7 @@ class AFPRenderer(VerboseOutput): raise Exception(f"Unrecognized object with Tag ID {tag.source_tag_id}!") else: # As far as I can tell, pretty much only color and matrix stuff can be updated. - self.vprint(f"{prefix} Updating Object ID {tag.object_id} on Depth {tag.depth}") + self.vprint(f"{prefix} Updating Object ID {tag.object_id} on Depth {tag.depth}", component="tags") obj.mult_color = new_mult_color obj.add_color = new_add_color obj.transform = new_transform @@ -875,7 +875,7 @@ class AFPRenderer(VerboseOutput): raise Exception("Cannot place a tag with no source ID and no update flags!") if tag.source_tag_id in self.__registered_objects: - self.vprint(f"{prefix} Placing Object {tag.source_tag_id} with Object ID {tag.object_id} onto Depth {tag.depth}") + self.vprint(f"{prefix} Placing Object {tag.source_tag_id} with Object ID {tag.object_id} onto Depth {tag.depth}", component="tags") newobj = self.__registered_objects[tag.source_tag_id] if isinstance(newobj, RegisteredShape): @@ -962,7 +962,7 @@ class AFPRenderer(VerboseOutput): raise Exception(f"Cannot find a shape or sprite with Tag ID {tag.source_tag_id}!") elif isinstance(tag, AP2RemoveObjectTag): - self.vprint(f"{prefix} Removing Object ID {tag.object_id} from Depth {tag.depth}") + self.vprint(f"{prefix} Removing Object ID {tag.object_id} from Depth {tag.depth}", component="tags") if tag.object_id != 0: # Remove the identified object by object ID and depth. @@ -1000,7 +1000,7 @@ class AFPRenderer(VerboseOutput): return None, True elif isinstance(tag, AP2DoActionTag): - self.vprint(f"{prefix} Execution action tag.") + self.vprint(f"{prefix} Execution action tag.", component="tags") self.__execute_bytecode(tag.bytecode, operating_clip, prefix=prefix + " ") # Didn't place a new clip. @@ -1029,7 +1029,7 @@ class AFPRenderer(VerboseOutput): return None, False elif isinstance(tag, AP2PlaceCameraTag): - self.vprint(f"{prefix} Place camera tag.") + self.vprint(f"{prefix} Place camera tag.", component="tags") self.__camera = PlacedCamera( tag.center, tag.focal_length, @@ -1131,10 +1131,10 @@ class AFPRenderer(VerboseOutput): prefix: str="", ) -> Image.Image: if not renderable.visible: - self.vprint(f"{prefix} Ignoring invisible placed object ID {renderable.object_id} from sprite {renderable.source.tag_id} on Depth {renderable.depth}") + self.vprint(f"{prefix} Ignoring invisible placed object ID {renderable.object_id} from sprite {renderable.source.tag_id} on Depth {renderable.depth}", component="render") return img - self.vprint(f"{prefix} Rendering placed object ID {renderable.object_id} from sprite {renderable.source.tag_id} onto Depth {renderable.depth}") + self.vprint(f"{prefix} Rendering placed object ID {renderable.object_id} from sprite {renderable.source.tag_id} onto Depth {renderable.depth}", component="render") # Compute the affine transformation matrix for this object. transform = renderable.transform.multiply(parent_transform).translate(Point.identity().subtract(renderable.rotation_origin)) @@ -1360,7 +1360,7 @@ class AFPRenderer(VerboseOutput): return False def __process_tags(self, clip: PlacedClip, only_dirty: bool, prefix: str = " ") -> bool: - self.vprint(f"{prefix}Handling {'dirty updates on ' if only_dirty else ''}placed clip {clip.object_id} at depth {clip.depth}") + self.vprint(f"{prefix}Handling {'dirty updates on ' if only_dirty else ''}placed clip {clip.object_id} at depth {clip.depth}", component="tags") # Track whether anything in ourselves or our children changes during this processing. changed = False @@ -1385,7 +1385,7 @@ class AFPRenderer(VerboseOutput): print("WARNING: Root clip was rewound, its possible this animation plays forever!") clip.rewind() - self.vprint(f"{prefix} Processing frame {clip.frame} on our way to frame {clip.requested_frame}") + self.vprint(f"{prefix} Processing frame {clip.frame} on our way to frame {clip.requested_frame}", component="tags") # Clips that are part of our own placed objects which we should handle. child_clips = [c for c in clip.placed_objects if isinstance(c, PlacedClip)] @@ -1399,7 +1399,7 @@ class AFPRenderer(VerboseOutput): # 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") + self.vprint(f"{prefix} Including orphaned tag {unplayed_tag} in frame evaluation", component="tags") played_tags.add(unplayed_tag) orphans.append(clip.source.tags[unplayed_tag]) @@ -1413,7 +1413,7 @@ class AFPRenderer(VerboseOutput): 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}") + self.vprint(f"{prefix} Sprite Tag ID: {clip.source.tag_id}, Current Tag: {frame.start_tag_offset + tagno}, Num Tags: {frame.num_tags}", component="tags") new_clip, clip_changed = self.__place(tag, clip, prefix=prefix) changed = changed or clip_changed @@ -1434,7 +1434,7 @@ class AFPRenderer(VerboseOutput): clip.requested_frame = None break - self.vprint(f"{prefix}Finished handling {'dirty updates on ' if only_dirty else ''}placed clip {clip.object_id} at depth {clip.depth}") + self.vprint(f"{prefix}Finished handling {'dirty updates on ' if only_dirty else ''}placed clip {clip.object_id} at depth {clip.depth}", component="tags") # Return if anything was modified. return changed @@ -1635,7 +1635,7 @@ class AFPRenderer(VerboseOutput): try: while root_clip.playing and not root_clip.finished: # Create a new image to render into. - self.vprint(f"Rendering frame {frameno + 1}/{len(root_clip.source.frames)}") + self.vprint(f"Rendering frame {frameno + 1}/{len(root_clip.source.frames)}", component="core") # Go through all registered clips, place all needed tags. changed = self.__process_tags(root_clip, False) @@ -1658,7 +1658,7 @@ class AFPRenderer(VerboseOutput): # If we're only rendering some frames, don't bother to do the draw operations # if we aren't going to return the frame. if only_frames and (frameno + 1) not in only_frames: - self.vprint(f"Skipped rendering frame {frameno + 1}/{len(root_clip.source.frames)}") + self.vprint(f"Skipped rendering frame {frameno + 1}/{len(root_clip.source.frames)}", component="core") last_rendered_frame = None frameno += 1 continue @@ -1680,11 +1680,11 @@ class AFPRenderer(VerboseOutput): ) else: # Nothing changed, make a copy of the previous render. - self.vprint(" Using previous frame render") + self.vprint(" Using previous frame render", component="core") curimage = last_rendered_frame.copy() # Return that frame, advance our bookkeeping. - self.vprint(f"Finished rendering frame {frameno + 1}/{len(root_clip.source.frames)}") + self.vprint(f"Finished rendering frame {frameno + 1}/{len(root_clip.source.frames)}", component="core") last_rendered_frame = curimage frameno += 1 yield curimage diff --git a/bemani/format/afp/swf.py b/bemani/format/afp/swf.py index 595f7eb..28fdde8 100644 --- a/bemani/format/afp/swf.py +++ b/bemani/format/afp/swf.py @@ -446,7 +446,7 @@ class AP2DefineEditTextTag(Tag): } -class SWF(TrackedCoverage, VerboseOutput): +class SWF(VerboseOutput, TrackedCoverage): def __init__( self, name: str, @@ -554,7 +554,7 @@ class SWF(TrackedCoverage, VerboseOutput): # The data directly follows, no pointer. offset_ptr = 2 - self.vprint(f"{prefix} Flags: {hex(flags)}, ByteCode Actual Offset: {hex(offset_ptr)}") + self.vprint(f"{prefix} Flags: {hex(flags)}, ByteCode Actual Offset: {hex(offset_ptr)}", component="bytecode") # Actually parse out the opcodes: actions: List[AP2Action] = [] @@ -568,7 +568,7 @@ class SWF(TrackedCoverage, VerboseOutput): if opcode in AP2Action.actions_without_params(): # Simple opcodes need no parsing, they can go directly onto the stack. - self.vprint(f"{prefix} {lineno}: {action_name}") + self.vprint(f"{prefix} {lineno}: {action_name}", component="bytecode") offset_ptr += 1 actions.append(AP2Action(lineno, opcode)) elif opcode == AP2Action.DEFINE_FUNCTION2: @@ -583,13 +583,13 @@ class SWF(TrackedCoverage, VerboseOutput): funcname = self.__get_string(funcname_offset) offset_ptr += 10 + (3 * bytecode_offset) - self.vprint(f"{prefix} {lineno}: {action_name} Flags: {hex(function_flags)}, Name: {funcname or ''}, ByteCode Offset: {hex(bytecode_offset)}, ByteCode Length: {hex(bytecode_count)}") + self.vprint(f"{prefix} {lineno}: {action_name} Flags: {hex(function_flags)}, Name: {funcname or ''}, ByteCode Offset: {hex(bytecode_offset)}, ByteCode Length: {hex(bytecode_count)}", component="bytecode") # No name for this chunk, it will only ever be decompiled and printed in the context of another # chunk. function = self.__parse_bytecode(None, datachunk[offset_ptr:(offset_ptr + bytecode_count)], string_offsets=string_offsets, prefix=prefix + " ") - self.vprint(f"{prefix} END_{action_name}") + self.vprint(f"{prefix} END_{action_name}", component="bytecode") actions.append(DefineFunction2Action(lineno, funcname, function_flags, function)) offset_ptr += bytecode_count @@ -597,7 +597,7 @@ class SWF(TrackedCoverage, VerboseOutput): obj_count = struct.unpack(">B", datachunk[(offset_ptr + 1):(offset_ptr + 2)])[0] offset_ptr += 2 - self.vprint(f"{prefix} {lineno}: {action_name}") + self.vprint(f"{prefix} {lineno}: {action_name}", component="bytecode") objects: List[Any] = [] @@ -608,44 +608,44 @@ class SWF(TrackedCoverage, VerboseOutput): if obj_to_create == 0x0: # Integer "0" object. objects.append(0) - self.vprint(f"{prefix} INTEGER: 0") + self.vprint(f"{prefix} INTEGER: 0", component="bytecode") elif obj_to_create == 0x1: # Float object, represented internally as a double. fval = struct.unpack(">f", datachunk[offset_ptr:(offset_ptr + 4)])[0] objects.append(fval) offset_ptr += 4 - self.vprint(f"{prefix} FLOAT: {fval}") + self.vprint(f"{prefix} FLOAT: {fval}", component="bytecode") elif obj_to_create == 0x2: # Null pointer object. objects.append(NULL) - self.vprint(f"{prefix} NULL") + self.vprint(f"{prefix} NULL", component="bytecode") elif obj_to_create == 0x3: # Undefined constant. objects.append(UNDEFINED) - self.vprint(f"{prefix} UNDEFINED") + self.vprint(f"{prefix} UNDEFINED", component="bytecode") elif obj_to_create == 0x4: # Register value. regno = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] objects.append(Register(regno)) offset_ptr += 1 - self.vprint(f"{prefix} REGISTER NO: {regno}") + self.vprint(f"{prefix} REGISTER NO: {regno}", component="bytecode") elif obj_to_create == 0x5: # Boolean "TRUE" object. objects.append(True) - self.vprint(f"{prefix} BOOLEAN: True") + self.vprint(f"{prefix} BOOLEAN: True", component="bytecode") elif obj_to_create == 0x6: # Boolean "FALSE" object. objects.append(False) - self.vprint(f"{prefix} BOOLEAN: False") + self.vprint(f"{prefix} BOOLEAN: False", component="bytecode") elif obj_to_create == 0x7: # Integer object. ival = struct.unpack(">i", datachunk[offset_ptr:(offset_ptr + 4)])[0] objects.append(ival) offset_ptr += 4 - self.vprint(f"{prefix} INTEGER: {ival}") + self.vprint(f"{prefix} INTEGER: {ival}", component="bytecode") elif obj_to_create == 0x8: # String constant object. const_offset = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] @@ -653,7 +653,7 @@ class SWF(TrackedCoverage, VerboseOutput): objects.append(const) offset_ptr += 1 - self.vprint(f"{prefix} STRING CONST: {const}") + self.vprint(f"{prefix} STRING CONST: {const}", component="bytecode") elif obj_to_create == 0x9: # String constant, but with 16 bits for the offset. Probably not used except # on the largest files. @@ -662,39 +662,39 @@ class SWF(TrackedCoverage, VerboseOutput): objects.append(const) offset_ptr += 2 - self.vprint(f"{prefix} STRING CONST: {const}") + self.vprint(f"{prefix} STRING CONST: {const}", component="bytecode") elif obj_to_create == 0xa: # NaN constant. objects.append(float("nan")) - self.vprint(f"{prefix} NAN") + self.vprint(f"{prefix} NAN", component="bytecode") elif obj_to_create == 0xb: # Infinity constant. objects.append(float("inf")) - self.vprint(f"{prefix} INFINITY") + self.vprint(f"{prefix} INFINITY", component="bytecode") elif obj_to_create == 0xc: # Pointer to "this" object, whatever currently is executing the bytecode. objects.append(THIS) - self.vprint(f"{prefix} POINTER TO THIS") + self.vprint(f"{prefix} POINTER TO THIS", component="bytecode") elif obj_to_create == 0xd: # Pointer to "root" object, which is the movieclip this bytecode exists in. objects.append(ROOT) - self.vprint(f"{prefix} POINTER TO ROOT") + self.vprint(f"{prefix} POINTER TO ROOT", component="bytecode") elif obj_to_create == 0xe: # Pointer to "parent" object, whatever currently is executing the bytecode. # This seems to be the parent of the movie clip, or the current movieclip # if that isn't set. objects.append(PARENT) - self.vprint(f"{prefix} POINTER TO PARENT") + self.vprint(f"{prefix} POINTER TO PARENT", component="bytecode") elif obj_to_create == 0xf: # Current movie clip. objects.append(CLIP) - self.vprint(f"{prefix} POINTER TO CURRENT MOVIECLIP") + self.vprint(f"{prefix} POINTER TO CURRENT MOVIECLIP", component="bytecode") elif obj_to_create == 0x10: # Property constant with no alias. propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x100 objects.append(StringConstant(propertyval)) offset_ptr += 1 - self.vprint(f"{prefix} PROPERTY CONST NAME: {StringConstant.property_to_name(propertyval)}") + self.vprint(f"{prefix} PROPERTY CONST NAME: {StringConstant.property_to_name(propertyval)}", component="bytecode") elif obj_to_create == 0x11: # Property constant referencing a string table entry. propertyval, reference = struct.unpack(">BB", datachunk[offset_ptr:(offset_ptr + 2)]) @@ -703,7 +703,7 @@ class SWF(TrackedCoverage, VerboseOutput): objects.append(StringConstant(propertyval, referenceval)) offset_ptr += 2 - self.vprint(f"{prefix} PROPERTY CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}") + self.vprint(f"{prefix} PROPERTY CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}", component="bytecode") elif obj_to_create == 0x12: # Same as above, but with allowance for a 16-bit constant offset. propertyval, reference = struct.unpack(">BH", datachunk[offset_ptr:(offset_ptr + 3)]) @@ -712,13 +712,13 @@ class SWF(TrackedCoverage, VerboseOutput): objects.append(StringConstant(propertyval, referenceval)) offset_ptr += 3 - self.vprint(f"{prefix} PROPERTY CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}") + self.vprint(f"{prefix} PROPERTY CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}", component="bytecode") elif obj_to_create == 0x13: # Class property name. propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x300 objects.append(StringConstant(propertyval)) offset_ptr += 1 - self.vprint(f"{prefix} CLASS CONST NAME: {StringConstant.property_to_name(propertyval)}") + self.vprint(f"{prefix} CLASS CONST NAME: {StringConstant.property_to_name(propertyval)}", component="bytecode") elif obj_to_create == 0x14: # Class property constant with alias. propertyval, reference = struct.unpack(">BB", datachunk[offset_ptr:(offset_ptr + 2)]) @@ -727,7 +727,7 @@ class SWF(TrackedCoverage, VerboseOutput): objects.append(StringConstant(propertyval, referenceval)) offset_ptr += 2 - self.vprint(f"{prefix} CLASS CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}") + self.vprint(f"{prefix} CLASS CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}", component="bytecode") # One would expect 0x15 to be identical to 0x12 but for class properties instead. However, it appears # that this has been omitted from game binaries. elif obj_to_create == 0x16: @@ -735,7 +735,7 @@ class SWF(TrackedCoverage, VerboseOutput): propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x400 objects.append(StringConstant(propertyval)) offset_ptr += 1 - self.vprint(f"{prefix} FUNC CONST NAME: {StringConstant.property_to_name(propertyval)}") + self.vprint(f"{prefix} FUNC CONST NAME: {StringConstant.property_to_name(propertyval)}", component="bytecode") elif obj_to_create == 0x17: # Func property name referencing a string table entry. propertyval, reference = struct.unpack(">BB", datachunk[offset_ptr:(offset_ptr + 2)]) @@ -744,14 +744,14 @@ class SWF(TrackedCoverage, VerboseOutput): objects.append(StringConstant(propertyval, referenceval)) offset_ptr += 2 - self.vprint(f"{prefix} FUNC CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}") + self.vprint(f"{prefix} FUNC CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}", component="bytecode") # Same comment with 0x15 applies here with 0x18. elif obj_to_create == 0x19: # Other property name. propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x200 objects.append(StringConstant(propertyval)) offset_ptr += 1 - self.vprint(f"{prefix} OTHER CONST NAME: {StringConstant.property_to_name(propertyval)}") + self.vprint(f"{prefix} OTHER CONST NAME: {StringConstant.property_to_name(propertyval)}", component="bytecode") elif obj_to_create == 0x1a: # Other property name referencing a string table entry. propertyval, reference = struct.unpack(">BB", datachunk[offset_ptr:(offset_ptr + 2)]) @@ -760,14 +760,14 @@ class SWF(TrackedCoverage, VerboseOutput): objects.append(StringConstant(propertyval, referenceval)) offset_ptr += 2 - self.vprint(f"{prefix} OTHER CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}") + self.vprint(f"{prefix} OTHER CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}", component="bytecode") # Same comment with 0x15 and 0x18 applies here with 0x1b. elif obj_to_create == 0x1c: # Event property name. propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x500 objects.append(StringConstant(propertyval)) offset_ptr += 1 - self.vprint(f"{prefix} EVENT CONST NAME: {StringConstant.property_to_name(propertyval)}") + self.vprint(f"{prefix} EVENT CONST NAME: {StringConstant.property_to_name(propertyval)}", component="bytecode") elif obj_to_create == 0x1d: # Event property name referencing a string table entry. propertyval, reference = struct.unpack(">BB", datachunk[offset_ptr:(offset_ptr + 2)]) @@ -776,14 +776,14 @@ class SWF(TrackedCoverage, VerboseOutput): objects.append(StringConstant(propertyval, referenceval)) offset_ptr += 2 - self.vprint(f"{prefix} EVENT CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}") + self.vprint(f"{prefix} EVENT CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}", component="bytecode") # Same comment with 0x15, 0x18 and 0x1b applies here with 0x1e. elif obj_to_create == 0x1f: # Key constants. propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x600 objects.append(StringConstant(propertyval)) offset_ptr += 1 - self.vprint(f"{prefix} KEY CONST NAME: {StringConstant.property_to_name(propertyval)}") + self.vprint(f"{prefix} KEY CONST NAME: {StringConstant.property_to_name(propertyval)}", component="bytecode") elif obj_to_create == 0x20: # Key property name referencing a string table entry. propertyval, reference = struct.unpack(">BB", datachunk[offset_ptr:(offset_ptr + 2)]) @@ -792,22 +792,22 @@ class SWF(TrackedCoverage, VerboseOutput): objects.append(StringConstant(propertyval, referenceval)) offset_ptr += 2 - self.vprint(f"{prefix} KEY CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}") + self.vprint(f"{prefix} KEY CONST NAME: {StringConstant.property_to_name(propertyval)}, ALIAS: {referenceval}", component="bytecode") # Same comment with 0x15, 0x18, 0x1b and 0x1e applies here with 0x21. elif obj_to_create == 0x22: # Pointer to global object. objects.append(GLOBAL) - self.vprint(f"{prefix} POINTER TO GLOBAL OBJECT") + self.vprint(f"{prefix} POINTER TO GLOBAL OBJECT", component="bytecode") elif obj_to_create == 0x23: # Negative infinity. objects.append(float("-inf")) - self.vprint(f"{prefix} -INFINITY") + self.vprint(f"{prefix} -INFINITY", component="bytecode") elif obj_to_create == 0x24: # Some other property name. propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x700 objects.append(StringConstant(propertyval)) offset_ptr += 1 - self.vprint(f"{prefix} ETC2 CONST NAME: {StringConstant.property_to_name(propertyval)}") + self.vprint(f"{prefix} ETC2 CONST NAME: {StringConstant.property_to_name(propertyval)}", component="bytecode") # Possibly in newer binaries, 0x25 and 0x26 are implemented as 8-bit and 16-bit alias pointer # versions of 0x24. elif obj_to_create == 0x27: @@ -815,7 +815,7 @@ class SWF(TrackedCoverage, VerboseOutput): propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x800 objects.append(StringConstant(propertyval)) offset_ptr += 1 - self.vprint(f"{prefix} ORGFUNC2 CONST NAME: {StringConstant.property_to_name(propertyval)}") + self.vprint(f"{prefix} ORGFUNC2 CONST NAME: {StringConstant.property_to_name(propertyval)}", component="bytecode") # Possibly in newer binaries, 0x28 and 0x29 are implemented as 8-bit and 16-bit alias pointer # versions of 0x27. elif obj_to_create == 0x2a: @@ -823,7 +823,7 @@ class SWF(TrackedCoverage, VerboseOutput): propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0x900 objects.append(StringConstant(propertyval)) offset_ptr += 1 - self.vprint(f"{prefix} ETCFUNC2 CONST NAME: {StringConstant.property_to_name(propertyval)}") + self.vprint(f"{prefix} ETCFUNC2 CONST NAME: {StringConstant.property_to_name(propertyval)}", component="bytecode") # Possibly in newer binaries, 0x2b and 0x2c are implemented as 8-bit and 16-bit alias pointer # versions of 0x2a. elif obj_to_create == 0x2d: @@ -831,7 +831,7 @@ class SWF(TrackedCoverage, VerboseOutput): propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0xa00 objects.append(StringConstant(propertyval)) offset_ptr += 1 - self.vprint(f"{prefix} EVENT2 CONST NAME: {StringConstant.property_to_name(propertyval)}") + self.vprint(f"{prefix} EVENT2 CONST NAME: {StringConstant.property_to_name(propertyval)}", component="bytecode") # Possibly in newer binaries, 0x2e and 0x2f are implemented as 8-bit and 16-bit alias pointer # versions of 0x2d. elif obj_to_create == 0x30: @@ -839,7 +839,7 @@ class SWF(TrackedCoverage, VerboseOutput): propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0xb00 objects.append(StringConstant(propertyval)) offset_ptr += 1 - self.vprint(f"{prefix} EVENT METHOD CONST NAME: {StringConstant.property_to_name(propertyval)}") + self.vprint(f"{prefix} EVENT METHOD CONST NAME: {StringConstant.property_to_name(propertyval)}", component="bytecode") # Possibly in newer binaries, 0x31 and 0x32 are implemented as 8-bit and 16-bit alias pointer # versions of 0x30. elif obj_to_create == 0x33: @@ -848,13 +848,13 @@ class SWF(TrackedCoverage, VerboseOutput): objects.append(int64) offset_ptr += 8 - self.vprint(f"{prefix} INTEGER: {int64}") + self.vprint(f"{prefix} INTEGER: {int64}", component="bytecode") elif obj_to_create == 0x34: # Some other property names. propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0xc00 objects.append(StringConstant(propertyval)) offset_ptr += 1 - self.vprint(f"{prefix} GENERIC CONST NAME: {StringConstant.property_to_name(propertyval)}") + self.vprint(f"{prefix} GENERIC CONST NAME: {StringConstant.property_to_name(propertyval)}", component="bytecode") # Possibly in newer binaries, 0x35 and 0x36 are implemented as 8-bit and 16-bit alias pointer # versions of 0x34. elif obj_to_create == 0x37: @@ -863,13 +863,13 @@ class SWF(TrackedCoverage, VerboseOutput): objects.append(ival) offset_ptr += 1 - self.vprint(f"{prefix} INTEGER: {ival}") + self.vprint(f"{prefix} INTEGER: {ival}", component="bytecode") elif obj_to_create == 0x38: # Some other property names. propertyval = struct.unpack(">B", datachunk[offset_ptr:(offset_ptr + 1)])[0] + 0xd00 objects.append(StringConstant(propertyval)) offset_ptr += 1 - self.vprint(f"{prefix} GENERIC2 CONST NAME: {StringConstant.property_to_name(propertyval)}") + self.vprint(f"{prefix} GENERIC2 CONST NAME: {StringConstant.property_to_name(propertyval)}", component="bytecode") # Possibly in newer binaries, 0x39 and 0x3a are implemented as 8-bit and 16-bit alias pointer # versions of 0x38. else: @@ -877,14 +877,14 @@ class SWF(TrackedCoverage, VerboseOutput): obj_count -= 1 - self.vprint(f"{prefix} END_{action_name}") + self.vprint(f"{prefix} END_{action_name}", component="bytecode") actions.append(PushAction(lineno, objects)) elif opcode == AP2Action.INIT_REGISTER: obj_count = struct.unpack(">B", datachunk[(offset_ptr + 1):(offset_ptr + 2)])[0] offset_ptr += 2 - self.vprint(f"{prefix} {lineno}: {action_name}") + self.vprint(f"{prefix} {lineno}: {action_name}", component="bytecode") init_registers: List[Register] = [] while obj_count > 0: @@ -893,15 +893,15 @@ class SWF(TrackedCoverage, VerboseOutput): offset_ptr += 1 obj_count -= 1 - self.vprint(f"{prefix} REGISTER NO: {register_no}") - self.vprint(f"{prefix} END_{action_name}") + self.vprint(f"{prefix} REGISTER NO: {register_no}", component="bytecode") + self.vprint(f"{prefix} END_{action_name}", component="bytecode") actions.append(InitRegisterAction(lineno, init_registers)) elif opcode == AP2Action.STORE_REGISTER: obj_count = struct.unpack(">B", datachunk[(offset_ptr + 1):(offset_ptr + 2)])[0] offset_ptr += 2 - self.vprint(f"{prefix} {lineno}: {action_name}") + self.vprint(f"{prefix} {lineno}: {action_name}", component="bytecode") store_registers: List[Register] = [] while obj_count > 0: @@ -910,17 +910,17 @@ class SWF(TrackedCoverage, VerboseOutput): offset_ptr += 1 obj_count -= 1 - self.vprint(f"{prefix} REGISTER NO: {register_no}") - self.vprint(f"{prefix} END_{action_name}") + self.vprint(f"{prefix} REGISTER NO: {register_no}", component="bytecode") + self.vprint(f"{prefix} END_{action_name}", component="bytecode") actions.append(StoreRegisterAction(lineno, store_registers, preserve_stack=True)) elif opcode == AP2Action.STORE_REGISTER2: register_no = struct.unpack(">B", datachunk[(offset_ptr + 1):(offset_ptr + 2)])[0] offset_ptr += 2 - self.vprint(f"{prefix} {lineno}: {action_name}") - self.vprint(f"{prefix} REGISTER NO: {register_no}") - self.vprint(f"{prefix} END_{action_name}") + self.vprint(f"{prefix} {lineno}: {action_name}", component="bytecode") + self.vprint(f"{prefix} REGISTER NO: {register_no}", component="bytecode") + self.vprint(f"{prefix} END_{action_name}", component="bytecode") actions.append(StoreRegisterAction(lineno, [Register(register_no)], preserve_stack=False)) elif opcode == AP2Action.IF: @@ -928,21 +928,21 @@ class SWF(TrackedCoverage, VerboseOutput): jump_if_true_offset += (lineno + 3) offset_ptr += 3 - self.vprint(f"{prefix} {lineno}: Offset If True: {jump_if_true_offset}") + self.vprint(f"{prefix} {lineno}: Offset If True: {jump_if_true_offset}", component="bytecode") actions.append(IfAction(lineno, IfAction.COMP_IS_TRUE, jump_if_true_offset)) elif opcode == AP2Action.IF2: if2_type, jump_if_true_offset = struct.unpack(">Bh", datachunk[(offset_ptr + 1):(offset_ptr + 4)]) jump_if_true_offset += (lineno + 4) offset_ptr += 4 - self.vprint(f"{prefix} {lineno}: {action_name} {IfAction.comparison_to_str(if2_type)}, Offset If True: {jump_if_true_offset}") + self.vprint(f"{prefix} {lineno}: {action_name} {IfAction.comparison_to_str(if2_type)}, Offset If True: {jump_if_true_offset}", component="bytecode") actions.append(IfAction(lineno, if2_type, jump_if_true_offset)) elif opcode == AP2Action.JUMP: jump_offset = struct.unpack(">h", datachunk[(offset_ptr + 1):(offset_ptr + 3)])[0] jump_offset += (lineno + 3) offset_ptr += 3 - self.vprint(f"{prefix} {lineno}: {action_name} Offset: {jump_offset}") + self.vprint(f"{prefix} {lineno}: {action_name} Offset: {jump_offset}", component="bytecode") actions.append(JumpAction(lineno, jump_offset)) elif opcode == AP2Action.WITH: skip_offset = struct.unpack(">H", datachunk[(offset_ptr + 1):(offset_ptr + 3)])[0] @@ -952,31 +952,31 @@ class SWF(TrackedCoverage, VerboseOutput): # represents... unknown_data = datachunk[offset_ptr:(offset_ptr + skip_offset)] offset_ptr += skip_offset - self.vprint(f"{prefix} {lineno}: {action_name} Unknown Data Length: {skip_offset}") + self.vprint(f"{prefix} {lineno}: {action_name} Unknown Data Length: {skip_offset}", component="bytecode") actions.append(WithAction(lineno, unknown_data)) elif opcode == AP2Action.ADD_NUM_VARIABLE: amount_to_add = struct.unpack(">b", datachunk[(offset_ptr + 1):(offset_ptr + 2)])[0] offset_ptr += 2 - self.vprint(f"{prefix} {lineno}: {action_name} Add Value: {amount_to_add}") + self.vprint(f"{prefix} {lineno}: {action_name} Add Value: {amount_to_add}", component="bytecode") actions.append(AddNumVariableAction(lineno, amount_to_add)) elif opcode == AP2Action.GET_URL2: get_url_action = struct.unpack(">B", datachunk[(offset_ptr + 1):(offset_ptr + 2)])[0] offset_ptr += 2 - self.vprint(f"{prefix} {lineno}: {action_name} URL Action: {get_url_action >> 6}") + self.vprint(f"{prefix} {lineno}: {action_name} URL Action: {get_url_action >> 6}", component="bytecode") actions.append(GetURL2Action(lineno, get_url_action >> 6)) elif opcode == AP2Action.START_DRAG: constraint = struct.unpack(">b", datachunk[(offset_ptr + 1):(offset_ptr + 2)])[0] offset_ptr += 2 - self.vprint(f"{prefix} {lineno}: {action_name} Constrain Mouse: {'yes' if constraint > 0 else ('no' if constraint == 0 else 'check stack')}") + self.vprint(f"{prefix} {lineno}: {action_name} Constrain Mouse: {'yes' if constraint > 0 else ('no' if constraint == 0 else 'check stack')}", component="bytecode") actions.append(StartDragAction(lineno, constrain=True if constraint > 0 else (False if constraint == 0 else None))) elif opcode == AP2Action.ADD_NUM_REGISTER: register_no, amount_to_add = struct.unpack(">Bb", datachunk[(offset_ptr + 1):(offset_ptr + 3)]) offset_ptr += 3 - self.vprint(f"{prefix} {lineno}: {action_name} Register No: {register_no}, Add Value: {amount_to_add}") + self.vprint(f"{prefix} {lineno}: {action_name} Register No: {register_no}, Add Value: {amount_to_add}", component="bytecode") actions.append(AddNumRegisterAction(lineno, Register(register_no), amount_to_add)) elif opcode == AP2Action.GOTO_FRAME2: flags = struct.unpack(">B", datachunk[(offset_ptr + 1):(offset_ptr + 2)])[0] @@ -994,7 +994,7 @@ class SWF(TrackedCoverage, VerboseOutput): else: additional_frames = 0 - self.vprint(f"{prefix} {lineno}: {action_name} AND {post} Additional Frames: {additional_frames}") + self.vprint(f"{prefix} {lineno}: {action_name} AND {post} Additional Frames: {additional_frames}", component="bytecode") actions.append(GotoFrame2Action(lineno, additional_frames, stop=bool(flags & 0x1))) else: raise Exception(f"Can't advance, no handler for opcode {opcode} ({hex(opcode)})!") @@ -1023,7 +1023,7 @@ class SWF(TrackedCoverage, VerboseOutput): # I'm not sure what the unknown value is. It doesn't seem to be parsed by either BishiBashi or Jubeat # when I've looked, but it does appear to be non-zero sometimes in Pop'n Music animations. shape_reference = f"{self.exported_name}_shape{shape_id}" - self.vprint(f"{prefix} Tag ID: {shape_id}, AFP Reference: {shape_reference}, Unknown: {unknown}") + self.vprint(f"{prefix} Tag ID: {shape_id}, AFP Reference: {shape_reference}, Unknown: {unknown}", component="tags") return AP2ShapeTag(shape_id, shape_reference) elif tagid == AP2Tag.AP2_DEFINE_SPRITE: @@ -1038,7 +1038,7 @@ class SWF(TrackedCoverage, VerboseOutput): subtags_offset = struct.unpack("> 16) & 0xFF) / 255.0 multcolor.b = float((rgba >> 8) & 0xFF) / 255.0 multcolor.a = float(rgba & 0xFF) / 255.0 - self.vprint(f"{prefix} Mult Color: {multcolor}") + self.vprint(f"{prefix} Mult Color: {multcolor}", component="tags") multdisplayed = True if flags & 0x4000: @@ -1257,16 +1258,16 @@ class SWF(TrackedCoverage, VerboseOutput): addcolor.g = float((rgba >> 16) & 0xFF) / 255.0 addcolor.b = float((rgba >> 8) & 0xFF) / 255.0 addcolor.a = float(rgba & 0xFF) / 255.0 - self.vprint(f"{prefix} Add Color: {addcolor}") + self.vprint(f"{prefix} Add Color: {addcolor}", component="tags") adddisplayed = True # For easier debugging, display the default color when the color # is being used. if flags & 0x8: if not multdisplayed: - self.vprint(f"{prefix} Mult Color: {multcolor}") + self.vprint(f"{prefix} Mult Color: {multcolor}", component="tags") if not adddisplayed: - self.vprint(f"{prefix} Add Color: {addcolor}") + self.vprint(f"{prefix} Add Color: {addcolor}", component="tags") bytecodes: Dict[int, List[ByteCode]] = {} if flags & 0x80: @@ -1292,7 +1293,7 @@ class SWF(TrackedCoverage, VerboseOutput): for i, bytecode_offset in enumerate(bytecode_offsets[:-1]): beginning_to_end[bytecode_offset] = bytecode_offsets[i + 1] - self.vprint(f"{prefix} Event Triggers, Count: {count}") + self.vprint(f"{prefix} Event Triggers, Count: {count}", component="tags") for evt in range(count): evt_offset = running_pointer + 12 + (evt * 8) evt_flags, _, keycode, bytecode_offset = struct.unpack("> 24) & 0xFF) / 255.0, ) - self.vprint(f"{prefix} Font Tag: {font_tag}, Font Height: {font_height}, X: {xpos}, Y: {ypos}, Count of Sub-Entries: {sub_data_count}, Color: {color}") + self.vprint(f"{prefix} Font Tag: {font_tag}, Font Height: {font_height}, X: {xpos}, Y: {ypos}, Count of Sub-Entries: {sub_data_count}, Color: {color}", component="tags") base_offset = dataoffset + (sub_data_offset * 4) + sub_data_base_offset offsets: List[AP2TextChar] = [] @@ -1712,7 +1713,7 @@ class SWF(TrackedCoverage, VerboseOutput): entry_width = round(float(xoff) / 20.0, 5) offsets.append(AP2TextChar(font_text_index, entry_width)) - self.vprint(f"{prefix} Font Text Index: {font_text_index}, X: {xpos}, Width: {entry_width}") + self.vprint(f"{prefix} Font Text Index: {font_text_index}, X: {xpos}, Width: {entry_width}", component="tags") # Make room for next character. xpos = round(xpos + entry_width, 5) @@ -1741,16 +1742,16 @@ class SWF(TrackedCoverage, VerboseOutput): rgba, f1, f2, f3, f4, variable_name_offset, default_text_offset = struct.unpack("> 16) & 0xFF) / 255.0, a=((rgba >> 24) & 0xFF) / 255.0, ) - self.vprint(f"{prefix} Text Color: {color}") + self.vprint(f"{prefix} Text Color: {color}", component="tags") - self.vprint(f"{prefix} Unk1: {unk1}, Unk2: {unk2}, Unk3: {unk3}, Unk4: {unk4}") + self.vprint(f"{prefix} Unk1: {unk1}, Unk2: {unk2}, Unk3: {unk3}, Unk4: {unk4}", component="tags") # flags & 0x20 means something with offset 16-18. # flags & 0x200 is unk str below is a HTML tag. @@ -1768,7 +1769,7 @@ class SWF(TrackedCoverage, VerboseOutput): if flags & 0x80: # Has some sort of string pointer. default_text = self.__get_string(default_text_offset) or None - self.vprint(f"{prefix} Default Text: {default_text}") + self.vprint(f"{prefix} Default Text: {default_text}", component="tags") else: default_text = None @@ -1780,7 +1781,7 @@ class SWF(TrackedCoverage, VerboseOutput): _0x2c_offset, _0x2e_offset, another_offset = struct.unpack("> 2) & 0x3}, Unk4-2: {(unk4 & 0x3)}") + self.vprint(f"{prefix} {label} Flags: {hex(flags)}, Unk3: {unk3}, Unk4-1: {(unk4 >> 2) & 0x3}, Unk4-2: {(unk4 & 0x3)}", component="tags") unprocessed_flags = flags if flags & 0x1: @@ -1806,7 +1807,7 @@ class SWF(TrackedCoverage, VerboseOutput): # subtracted from the first value, and that is multiplied by some percentage, and then the # second value is added back in. - self.vprint(f"{prefix} Unknown Int1: {int1}, Int2: {int2}") + self.vprint(f"{prefix} Unknown Int1: {int1}, Int2: {int2}", component="tags") if flags & 0x12: intval, src_ptr = struct.unpack("> 24) & 0xFF) / 255.0, ) - self.vprint(f"{prefix} Start Color: {color1}, End Color: {color2}") + self.vprint(f"{prefix} Start Color: {color1}, End Color: {color2}", component="tags") if flags & 0x8: a1, d1, a2, d2, b1, c1, b2, c2, tx1, ty1, tx2, ty2 = struct.unpack("> 16) & 0xFF) / 255.0 multcolor.b = float((rgba >> 8) & 0xFF) / 255.0 multcolor.a = float(rgba & 0xFF) / 255.0 - self.vprint(f"{prefix} Mult Color: {multcolor}") + self.vprint(f"{prefix} Mult Color: {multcolor}", component="tags") if flags & 0x4000: # Additive color present, smaller integers. @@ -2023,7 +2024,7 @@ class SWF(TrackedCoverage, VerboseOutput): addcolor.g = float((rgba >> 16) & 0xFF) / 255.0 addcolor.b = float((rgba >> 8) & 0xFF) / 255.0 addcolor.a = float(rgba & 0xFF) / 255.0 - self.vprint(f"{prefix} Add Color: {addcolor}") + self.vprint(f"{prefix} Add Color: {addcolor}", component="tags") if flags & 0x8000: # Some sort of filter data? Not sure what this is either. Needs more investigation @@ -2037,7 +2038,7 @@ class SWF(TrackedCoverage, VerboseOutput): # all in the range of 0-7, corresponding to some sort of filter. They get sizes # looked up and I presume there's data following this corresponding to those sizes. # I don't know however as I've not encountered data with this bit. - self.vprint(f"{prefix} Unknown Filter data Count: {count}, Size: {filter_size}") + self.vprint(f"{prefix} Unknown Filter data Count: {count}, Size: {filter_size}", component="tags") for _ in range(bytecode_count): loc = struct.unpack("> 20) & 0xFFF frames.append(Frame(start_tag_offset, num_tags_to_play)) - self.vprint(f"{prefix} Frame Start Tag: {start_tag_offset}, Count: {num_tags_to_play}") + self.vprint(f"{prefix} Frame Start Tag: {start_tag_offset}, Count: {num_tags_to_play}", component="tags") for j in range(num_tags_to_play): if start_tag_offset + j in tag_to_frame: raise Exception("Logic error!") @@ -2165,7 +2166,7 @@ class SWF(TrackedCoverage, VerboseOutput): # Now, parse regular tags. tags: List[Tag] = [] - self.vprint(f"{prefix}Number of Tags: {tags_count}") + self.vprint(f"{prefix}Number of Tags: {tags_count}", component="tags") for i in range(tags_count): tag = struct.unpack(" 0x200000: raise Exception(f"Invalid tag size {size} ({hex(size)})") - self.vprint(f"{prefix} Tag: {hex(tagid)} ({AP2Tag.tag_to_name(tagid)}), Size: {hex(size)}, Offset: {hex(tags_offset + 4)}") + self.vprint(f"{prefix} Tag: {hex(tagid)} ({AP2Tag.tag_to_name(tagid)}), Size: {hex(size)}, Offset: {hex(tags_offset + 4)}", component="tags") tags.append(self.__parse_tag(ap2_version, afp_version, ap2data, tagid, size, tags_offset + 4, sprite, tag_to_frame.get(i, 'orphan'), prefix=prefix)) tags_offset += ((size + 3) & 0xFFFFFFFC) + 4 # Skip past tag header and data, rounding to the nearest 4 bytes. # Finally, parse frame labels - self.vprint(f"{prefix}Number of Frame Labels: {name_reference_count}, Flags: {hex(name_reference_flags)}") + self.vprint(f"{prefix}Number of Frame Labels: {name_reference_count}, Flags: {hex(name_reference_flags)}", component="tags") labels: Dict[str, int] = {} for _ in range(name_reference_count): frameno, stringoffset = struct.unpack("= len(self.frames): diff --git a/bemani/format/afp/util.py b/bemani/format/afp/util.py index bb68e13..45398cc 100644 --- a/bemani/format/afp/util.py +++ b/bemani/format/afp/util.py @@ -50,6 +50,8 @@ class TrackedCoverageManager: class TrackedCoverage: def __init__(self) -> None: + super().__init__() + self.coverage: List[bool] = [] self._tracking: bool = False @@ -138,12 +140,17 @@ class VerboseOutputManager: class VerboseOutput: - def __init__(self) -> None: + def __init__(self, components: List[str] = []) -> None: + super().__init__() + self.verbose: bool = False + self.components: List[str] = components or [] def debugging(self, verbose: bool) -> VerboseOutputManager: return VerboseOutputManager(self, verbose) def vprint(self, *args: Any, **kwargs: Any) -> None: - if self.verbose: + should_print = self.verbose or (kwargs.get('component', None) in self.components) + kwargs = {k: v for k, v in kwargs.items() if k != 'component'} + if should_print: print(*args, **kwargs, file=sys.stderr)