Created
March 19, 2022 01:29
-
-
Save EllipticEllipsis/31e4584cf002497f9f7729fbc4fab368 to your computer and use it in GitHub Desktop.
Convert a raw number into flag defines
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| import argparse | |
| from typing import List | |
| import dataclasses # cursed | |
| @dataclasses.dataclass | |
| class Flag: | |
| mask: int | |
| name: str | |
| @dataclasses.dataclass | |
| class FlagCategory: | |
| size: int | |
| all: str | |
| flags: List[Flag] # Individual flags | |
| flag_combos: List[Flag] # Combinations, must go in order of priority/size | |
| def count_set_bits(n): | |
| return bin(n).count("1") | |
| ACTOR_FLAGS = FlagCategory( | |
| 32, | |
| "0xFFFFFFFF", | |
| [ | |
| Flag(0x00000001, "ACTOR_FLAG_1"), | |
| Flag(0x00000002, "ACTOR_FLAG_2"), | |
| Flag(0x00000004, "ACTOR_FLAG_4"), | |
| Flag(0x00000008, "ACTOR_FLAG_8"), | |
| Flag(0x00000010, "ACTOR_FLAG_10"), | |
| Flag(0x00000020, "ACTOR_FLAG_20"), | |
| Flag(0x00000040, "ACTOR_FLAG_40"), | |
| Flag(0x00000080, "ACTOR_FLAG_80"), | |
| Flag(0x00000100, "ACTOR_FLAG_100"), | |
| Flag(0x00000200, "ACTOR_FLAG_200"), | |
| Flag(0x00000400, "ACTOR_FLAG_400"), | |
| Flag(0x00000800, "ACTOR_FLAG_800"), | |
| Flag(0x00001000, "ACTOR_FLAG_1000"), | |
| Flag(0x00002000, "ACTOR_FLAG_2000"), | |
| Flag(0x00004000, "ACTOR_FLAG_4000"), | |
| Flag(0x00008000, "ACTOR_FLAG_8000"), | |
| Flag(0x00010000, "ACTOR_FLAG_10000"), | |
| Flag(0x00020000, "ACTOR_FLAG_20000"), | |
| Flag(0x00040000, "ACTOR_FLAG_40000"), | |
| Flag(0x00080000, "ACTOR_FLAG_80000"), | |
| Flag(0x00100000, "ACTOR_FLAG_100000"), | |
| Flag(0x00200000, "ACTOR_FLAG_200000"), | |
| Flag(0x00400000, "ACTOR_FLAG_400000"), | |
| Flag(0x00800000, "ACTOR_FLAG_800000"), | |
| Flag(0x01000000, "ACTOR_FLAG_1000000"), | |
| Flag(0x02000000, "ACTOR_FLAG_2000000"), | |
| Flag(0x04000000, "ACTOR_FLAG_4000000"), | |
| Flag(0x08000000, "ACTOR_FLAG_8000000"), | |
| Flag(0x10000000, "ACTOR_FLAG_10000000"), | |
| Flag(0x20000000, "ACTOR_FLAG_20000000"), | |
| Flag(0x40000000, "ACTOR_FLAG_40000000"), | |
| Flag(0x80000000, "ACTOR_FLAG_80000000"), | |
| ], | |
| [ | |
| Flag(0x30, "ACTOR_FLAGS_30"), | |
| ], | |
| ) | |
| PLAYER_STATE_1_FLAGS = FlagCategory( | |
| 32, | |
| "0xFFFFFFFF", | |
| [ | |
| Flag(0x00000001, "PLAYER_STATE1_1"), | |
| Flag(0x00000002, "PLAYER_STATE1_2"), | |
| Flag(0x00000004, "PLAYER_STATE1_4"), | |
| Flag(0x00000008, "PLAYER_STATE1_8"), | |
| Flag(0x00000010, "PLAYER_STATE1_10"), | |
| Flag(0x00000020, "PLAYER_STATE1_20"), | |
| Flag(0x00000040, "PLAYER_STATE1_40"), | |
| Flag(0x00000080, "PLAYER_STATE1_80"), | |
| Flag(0x00000100, "PLAYER_STATE1_100"), | |
| Flag(0x00000200, "PLAYER_STATE1_200"), | |
| Flag(0x00000400, "PLAYER_STATE1_400"), | |
| Flag(0x00000800, "PLAYER_STATE1_800"), | |
| Flag(0x00001000, "PLAYER_STATE1_1000"), | |
| Flag(0x00002000, "PLAYER_STATE1_2000"), | |
| Flag(0x00004000, "PLAYER_STATE1_4000"), | |
| Flag(0x00008000, "PLAYER_STATE1_8000"), | |
| Flag(0x00010000, "PLAYER_STATE1_10000"), | |
| Flag(0x00020000, "PLAYER_STATE1_20000"), | |
| Flag(0x00040000, "PLAYER_STATE1_40000"), | |
| Flag(0x00080000, "PLAYER_STATE1_80000"), | |
| Flag(0x00100000, "PLAYER_STATE1_100000"), | |
| Flag(0x00200000, "PLAYER_STATE1_200000"), | |
| Flag(0x00400000, "PLAYER_STATE1_400000"), | |
| Flag(0x00800000, "PLAYER_STATE1_800000"), | |
| Flag(0x01000000, "PLAYER_STATE1_1000000"), | |
| Flag(0x02000000, "PLAYER_STATE1_2000000"), | |
| Flag(0x04000000, "PLAYER_STATE1_4000000"), | |
| Flag(0x08000000, "PLAYER_STATE1_8000000"), | |
| Flag(0x10000000, "PLAYER_STATE1_10000000"), | |
| Flag(0x20000000, "PLAYER_STATE1_20000000"), | |
| Flag(0x40000000, "PLAYER_STATE1_40000000"), | |
| Flag(0x80000000, "PLAYER_STATE1_80000000"), | |
| ], | |
| [], | |
| ) | |
| PLAYER_STATE_2_FLAGS = FlagCategory( | |
| 32, | |
| "0xFFFFFFFF", | |
| [ | |
| Flag(0x00000001, "PLAYER_STATE2_1"), | |
| Flag(0x00000002, "PLAYER_STATE2_2"), | |
| Flag(0x00000004, "PLAYER_STATE2_4"), | |
| Flag(0x00000008, "PLAYER_STATE2_8"), | |
| Flag(0x00000010, "PLAYER_STATE2_10"), | |
| Flag(0x00000020, "PLAYER_STATE2_20"), | |
| Flag(0x00000040, "PLAYER_STATE2_40"), | |
| Flag(0x00000080, "PLAYER_STATE2_80"), | |
| Flag(0x00000100, "PLAYER_STATE2_100"), | |
| Flag(0x00000200, "PLAYER_STATE2_200"), | |
| Flag(0x00000400, "PLAYER_STATE2_400"), | |
| Flag(0x00000800, "PLAYER_STATE2_800"), | |
| Flag(0x00001000, "PLAYER_STATE2_1000"), | |
| Flag(0x00002000, "PLAYER_STATE2_2000"), | |
| Flag(0x00004000, "PLAYER_STATE2_4000"), | |
| Flag(0x00008000, "PLAYER_STATE2_8000"), | |
| Flag(0x00010000, "PLAYER_STATE2_10000"), | |
| Flag(0x00020000, "PLAYER_STATE2_20000"), | |
| Flag(0x00040000, "PLAYER_STATE2_40000"), | |
| Flag(0x00080000, "PLAYER_STATE2_80000"), | |
| Flag(0x00100000, "PLAYER_STATE2_100000"), | |
| Flag(0x00200000, "PLAYER_STATE2_200000"), | |
| Flag(0x00400000, "PLAYER_STATE2_400000"), | |
| Flag(0x00800000, "PLAYER_STATE2_800000"), | |
| Flag(0x01000000, "PLAYER_STATE2_1000000"), | |
| Flag(0x02000000, "PLAYER_STATE2_2000000"), | |
| Flag(0x04000000, "PLAYER_STATE2_4000000"), | |
| Flag(0x08000000, "PLAYER_STATE2_8000000"), | |
| Flag(0x10000000, "PLAYER_STATE2_10000000"), | |
| Flag(0x20000000, "PLAYER_STATE2_20000000"), | |
| Flag(0x40000000, "PLAYER_STATE2_40000000"), | |
| Flag(0x80000000, "PLAYER_STATE2_80000000"), | |
| ], | |
| [], | |
| ) | |
| PLAYER_STATE_3_FLAGS = FlagCategory( | |
| 32, | |
| "0xFFFFFFFF", | |
| [ | |
| Flag(0x00000001, "PLAYER_STATE3_1"), | |
| Flag(0x00000002, "PLAYER_STATE3_2"), | |
| Flag(0x00000004, "PLAYER_STATE3_4"), | |
| Flag(0x00000008, "PLAYER_STATE3_8"), | |
| Flag(0x00000010, "PLAYER_STATE3_10"), | |
| Flag(0x00000020, "PLAYER_STATE3_20"), | |
| Flag(0x00000040, "PLAYER_STATE3_40"), | |
| Flag(0x00000080, "PLAYER_STATE3_80"), | |
| Flag(0x00000100, "PLAYER_STATE3_100"), | |
| Flag(0x00000200, "PLAYER_STATE3_200"), | |
| Flag(0x00000400, "PLAYER_STATE3_400"), | |
| Flag(0x00000800, "PLAYER_STATE3_800"), | |
| Flag(0x00001000, "PLAYER_STATE3_1000"), | |
| Flag(0x00002000, "PLAYER_STATE3_2000"), | |
| Flag(0x00004000, "PLAYER_STATE3_4000"), | |
| Flag(0x00008000, "PLAYER_STATE3_8000"), | |
| Flag(0x00010000, "PLAYER_STATE3_10000"), | |
| Flag(0x00020000, "PLAYER_STATE3_20000"), | |
| Flag(0x00040000, "PLAYER_STATE3_40000"), | |
| Flag(0x00080000, "PLAYER_STATE3_80000"), | |
| Flag(0x00100000, "PLAYER_STATE3_100000"), | |
| Flag(0x00200000, "PLAYER_STATE3_200000"), | |
| Flag(0x00400000, "PLAYER_STATE3_400000"), | |
| Flag(0x00800000, "PLAYER_STATE3_800000"), | |
| Flag(0x01000000, "PLAYER_STATE3_1000000"), | |
| Flag(0x02000000, "PLAYER_STATE3_2000000"), | |
| Flag(0x04000000, "PLAYER_STATE3_4000000"), | |
| Flag(0x08000000, "PLAYER_STATE3_8000000"), | |
| Flag(0x10000000, "PLAYER_STATE3_10000000"), | |
| Flag(0x20000000, "PLAYER_STATE3_20000000"), | |
| Flag(0x40000000, "PLAYER_STATE3_40000000"), | |
| Flag(0x80000000, "PLAYER_STATE3_80000000"), | |
| ], | |
| [], | |
| ) | |
| OOT_DAMAGE_FLAGS = FlagCategory( | |
| 32, | |
| "0xFFFFFFFF", | |
| [ | |
| Flag(0x00000001, "DMG_DEKU_NUT"), | |
| Flag(0x00000002, "DMG_DEKU_STICK"), | |
| Flag(0x00000004, "DMG_SLINGSHOT"), | |
| Flag(0x00000008, "DMG_EXPLOSIVE"), | |
| Flag(0x00000010, "DMG_BOOMERANG"), | |
| Flag(0x00000020, "DMG_ARROW_NORMAL"), | |
| Flag(0x00000040, "DMG_HAMMER_SWING"), | |
| Flag(0x00000080, "DMG_HOOKSHOT"), | |
| Flag(0x00000100, "DMG_SLASH_KOKIRI"), | |
| Flag(0x00000200, "DMG_SLASH_MASTER"), | |
| Flag(0x00000400, "DMG_SLASH_GIANT"), | |
| Flag(0x00000800, "DMG_ARROW_FIRE"), | |
| Flag(0x00001000, "DMG_ARROW_ICE"), | |
| Flag(0x00002000, "DMG_ARROW_LIGHT"), | |
| Flag(0x00004000, "DMG_ARROW_UNK1"), | |
| Flag(0x00008000, "DMG_ARROW_UNK2"), | |
| Flag(0x00010000, "DMG_ARROW_UNK3"), | |
| Flag(0x00020000, "DMG_MAGIC_FIRE"), | |
| Flag(0x00040000, "DMG_MAGIC_ICE"), | |
| Flag(0x00080000, "DMG_MAGIC_LIGHT"), | |
| Flag(0x00100000, "DMG_SHIELD"), | |
| Flag(0x00200000, "DMG_MIR_RAY"), | |
| Flag(0x00400000, "DMG_SPIN_KOKIRI"), | |
| Flag(0x00800000, "DMG_SPIN_GIANT"), | |
| Flag(0x01000000, "DMG_SPIN_MASTER"), | |
| Flag(0x02000000, "DMG_JUMP_KOKIRI"), | |
| Flag(0x04000000, "DMG_JUMP_GIANT"), | |
| Flag(0x08000000, "DMG_JUMP_MASTER"), | |
| Flag(0x10000000, "DMG_UNKNOWN_1"), | |
| Flag(0x20000000, "DMG_UNBLOCKABLE"), | |
| Flag(0x40000000, "DMG_HAMMER_JUMP"), | |
| Flag(0x80000000, "DMG_UNKNOWN_2"), | |
| ], | |
| [ | |
| Flag(0xFFCFFFFF, "DMG_DEFAULT"), | |
| Flag(0x0FC00700, "DMG_SWORD"), | |
| Flag(0x40000040, "DMG_HAMMER"), | |
| Flag(0x0001F8A4, "DMG_RANGED"), | |
| Flag(0x0001F820, "DMG_ARROW"), | |
| Flag(0x00020800, "DMG_FIRE"), | |
| Flag(0x00000700, "DMG_SLASH"), | |
| Flag(0x01C00000, "DMG_SPIN_ATTACK"), | |
| Flag(0x0E000000, "DMG_JUMP_SLASH"), | |
| ], | |
| ) | |
| def decompose_flags(args, flag_cat: FlagCategory) -> str: | |
| input = int(args.flags, 16) | |
| output = [] | |
| # print(f"{input:08X}") | |
| negated = False | |
| if count_set_bits(input) >= 20: | |
| negated = True | |
| input = ~input & ((1 << flag_cat.size) - 1) | |
| # Test combinations | |
| for flag in flag_cat.flag_combos: | |
| if input == 0: | |
| break | |
| # print(f"{flag.name}, {flag.mask & input:X}, {flag.mask:X}") | |
| if flag.mask & input == flag.mask: | |
| output.append(flag.name) | |
| input &= ~flag.mask | |
| # Test for remaining individuals | |
| for flag in flag_cat.flags: | |
| if input == 0: | |
| break | |
| if flag.mask & input == flag.mask: | |
| output.append(flag.name) | |
| input &= ~flag.mask | |
| assert ( | |
| input == 0 | |
| ), f"Is your input correct? It hasn't been completely decomposed: {input:X}" | |
| if negated: | |
| ret = " | ".join(output) if output != [] else flag_cat.all | |
| if len(output) > 1: | |
| ret = "(" + ret + ")" | |
| return "~" + ret | |
| else: | |
| ret = " | ".join(output) if output != [] else "0" | |
| if len(output) > 1: | |
| ret = "(" + ret + ")" | |
| return ret | |
| FLAG_TYPES = { | |
| "actor": ACTOR_FLAGS, | |
| "player_state_1": PLAYER_STATE_1_FLAGS, | |
| "player_state_2": PLAYER_STATE_2_FLAGS, | |
| "player_state_3": PLAYER_STATE_3_FLAGS, | |
| "oot_dmg": OOT_DAMAGE_FLAGS, | |
| } | |
| def main(): | |
| description = "" | |
| epilog = "" | |
| parser = argparse.ArgumentParser( | |
| description=description, | |
| epilog=epilog, | |
| formatter_class=argparse.RawTextHelpFormatter, | |
| ) | |
| parser.add_argument("flags", help="integer containing packed flags to decompose") | |
| parser.add_argument( | |
| "type", choices=FLAG_TYPES, help="type of flags to use in decomposition" | |
| ) | |
| # parser.add_argument("-n", "--negate", help="negate flags instead of printing all of them", action="store_true") | |
| args = parser.parse_args() | |
| # input = int(args.flags, 16) | |
| output = decompose_flags(args, FLAG_TYPES[args.type]) | |
| print(output) | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment