class predictionRequest: template_prediction = Dict( schema={ 'order_id': Int(coerce=True), 'store_id': Int(coerce=True), 'to_user_distance': Float(), 'to_user_elevation': Float(), 'total_earning': Int(coerce=True), 'created_at': Str() }) @classmethod def validate_request(cls, request: dict): return cls.template_prediction(request)
class BKAnimation(Animation): __slots__ = ( "null", "chain_hit", "chain_no_hit", "repeat", "probability", "hazard_damage", "footer_string", ) schema = Dict( { **Animation.schema.schema, **{ "null": UInt8, "chain_hit": UInt8, "chain_no_hit": UInt8, "repeat": UInt8, "probability": UInt16, "hazard_damage": UInt8, "footer_string": Str(), }, } ) def __init__(self): super(BKAnimation, self).__init__() self.null: int = 0 self.chain_hit: int = 0 self.chain_no_hit: int = 0 self.repeat: int = 0 self.probability: int = 0 self.hazard_damage: int = 0 self.footer_string: str = "" @staticmethod def get_name(index: int): if index in BK_ANIMATION_NAMES: return BK_ANIMATION_NAMES[index] return None def read(self, parser): self.null = parser.get_uint8() self.chain_hit = parser.get_uint8() self.chain_no_hit = parser.get_uint8() self.repeat = parser.get_uint8() self.probability = parser.get_uint16() self.hazard_damage = parser.get_uint8() self.footer_string = parser.get_var_str(size_includes_zero=True) super(BKAnimation, self).read(parser) return self def write(self, parser): parser.put_uint8(self.null) parser.put_uint8(self.chain_hit) parser.put_uint8(self.chain_no_hit) parser.put_uint8(self.repeat) parser.put_uint16(self.probability) parser.put_uint8(self.hazard_damage) parser.put_var_str(self.footer_string, size_includes_zero=True) super(BKAnimation, self).write(parser) def serialize(self): return { **super(BKAnimation, self).serialize(), **{ "null": self.null, "chain_hit": self.chain_hit, "chain_no_hit": self.chain_no_hit, "repeat": self.repeat, "probability": self.probability, "hazard_damage": self.hazard_damage, "footer_string": self.footer_string, }, } def unserialize(self, data): super(BKAnimation, self).unserialize(data) self.null = data["null"] self.chain_hit = data["chain_hit"] self.chain_no_hit = data["chain_no_hit"] self.repeat = data["repeat"] self.probability = data["probability"] self.hazard_damage = data["hazard_damage"] self.footer_string = data["footer_string"] return self
from validx import Dict, List, Str, Datetime, Bool from django.utils.dateparse import parse_datetime from datetime import timezone new_msg_validator = Dict( { "sender": Str(minlen=1, maxlen=64), "text": Str(minlen=1, maxlen=2048), "type": Str(minlen=1, maxlen=32), "time": Datetime(nullable=True, parser=parse_datetime, tz=timezone.utc), "tts": Bool(), "data": Str(minlen=0, maxlen=5120), "speech_override": Str(nullable=True, minlen=1, maxlen=2048), "seen": Bool(), }, defaults={ "type": "default", "time": None, "tts": True, "seen": False, "data": "", "speech_override": None, }, ) seen_messages_validator = List(Str(minlen=1, maxlen=32))
class Animation(DataObject): __slots__ = ( "start_x", "start_y", "base_string", "hit_coords", "extra_strings", "sprites", ) schema = Dict({ "start_x": Int16, "start_y": Int16, "base_string": Str(), "hit_coords": List( Dict({ "x": Int(min=-511, max=511), "null": Int(min=0, max=0), "y": Int(min=-511, max=511), "frame_id": Int(min=0, max=63), })), "extra_strings": List(Str()), "sprites": List(Sprite.schema), }) def __init__(self): self.start_x: int = 0 self.start_y: int = 0 self.hit_coords: typing.List[HitCoordinate] = [] self.sprites: typing.List[Sprite] = [] self.base_string: str = "" self.extra_strings: typing.List[str] = [] def read(self, parser): self.start_x = parser.get_int16() self.start_y = parser.get_int16() assert parser.get_uint32() == 0 coord_count = parser.get_uint16() sprite_count = parser.get_uint8() self.hit_coords = [] for m in range(0, coord_count): a = parser.get_uint16() b = parser.get_uint16() x = 0x3FF & a y = 0x3FF & b self.hit_coords.append({ "x": x if x < 512 else x - 1024, "null": (a >> 10), "y": y if y < 512 else y - 1024, "frame_id": (b >> 10), }) self.base_string = parser.get_var_str() extra_str_count = parser.get_uint8() self.extra_strings = [ parser.get_var_str() for _ in range(extra_str_count) ] self.sprites = [Sprite().read(parser) for _ in range(sprite_count)] return self def write(self, parser): parser.put_int16(self.start_x) parser.put_int16(self.start_y) parser.put_uint32(0) parser.put_uint16(len(self.hit_coords)) parser.put_uint8(len(self.sprites)) for coord in self.hit_coords: frame_id = coord["frame_id"] null = coord["null"] x = coord["x"] y = coord["y"] tmp = frame_id & 0x3F tmp <<= 10 tmp |= y & 0x3FF tmp <<= 6 tmp |= null & 0x3F tmp <<= 10 tmp |= x & 0x3FF parser.put_uint32(tmp) parser.put_var_str(self.base_string) parser.put_uint8(len(self.extra_strings)) for extra_string in self.extra_strings: parser.put_var_str(extra_string) for sprite in self.sprites: sprite.write(parser) def serialize(self): return { "start_x": self.start_x, "start_y": self.start_y, "hit_coords": self.hit_coords, "sprites": [sprite.serialize() for sprite in self.sprites], "base_string": self.base_string, "extra_strings": self.extra_strings, } def unserialize(self, data): self.start_x = data["start_x"] self.start_y = data["start_y"] self.hit_coords = data["hit_coords"] self.sprites = [ Sprite().unserialize(sprite) for sprite in data["sprites"] ] self.base_string = data["base_string"] self.extra_strings = data["extra_strings"] return self
#: Set of reserved configuration keys. CONFIG_RESERVED_KEYS = {'becmd', 'hosts', 'logging', 'refresh'} #: List of logging levels. LOGGING_LEVELS = {'CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'NOTSET'} #: Logging format styles. LOGGING_STYLES = {'%', '{', '$'} #: Regular expression excluding all reserved configuration keys. RESERVED_KEYS_PATTERN = r'^(?:(?!{}).+)$'.format( r'|'.join(CONFIG_RESERVED_KEYS)) #: Validation schema for a host configuration. Host = Dict( { 'api_key': Str(nullable=False), 'host': Str(pattern=r'^[0-9A-Za-z\._-]+$', nullable=False), 'insecure_tls': Bool(), 'timeout': Float(), 'use_cache': Bool(), 'use_https': Bool(), }, dispose=[ 'default', ], ) #: Host configuration keys. HOST_CONFIG_KEYS = set(Host.schema) #: Host validator where the command line arguments are optional.
#!/bin/python # validation!! # https://validx.readthedocs.io/en/latest/usage.html?highlight=install from validx import Dict, List, Str, Int search_params = Dict( { "query": Str(minlen=3, maxlen=500), # Search query "tags": List(Str(pattern=r"^[\w]+$")), # Optional list of tags "limit": Int(min=0, max=100), # Pagination parameters "offset": Int(min=0), }, defaults={ "limit": 100, "offset": 0, }, optional=["tags"], ) # testing assert search_params({"query": u"Craft Beer"}) == { "query": "Craft Beer", "limit": 100, "offset": 0, } assert search_params({"query": u"Craft Beer", "offset": 100}) == { "query": u"Craft Beer", "limit": 100, "offset": 100,
class AFMove(Animation): __slots__ = ( "ai_opts", "pos_constraint", "unknown_4", "unknown_5", "unknown_6", "unknown_7", "unknown_8", "unknown_9", "unknown_10", "unknown_11", "next_animation_id", "category", "unknown_14", "scrap_amount", "successor_id", "damage_amount", "collision_opts", "extra_string_selector", "points", "move_string", "enemy_string", ) schema = Dict({ **Animation.schema.schema, **{ "ai_opts": UInt16, "pos_constraint": UInt16, "unknown_4": UInt8, "unknown_5": UInt8, "unknown_6": UInt8, "unknown_7": UInt8, "unknown_8": UInt8, "unknown_9": UInt8, "unknown_10": UInt8, "unknown_11": UInt8, "next_animation_id": UInt8, "category": UInt8, "unknown_14": UInt8, "scrap_amount": UInt8, "successor_id": UInt8, "damage_amount": UInt8, "collision_opts": UInt8, "extra_string_selector": UInt8, "points": UInt8, "move_string": Str(maxlen=21), "enemy_string": Str(), }, }) def __init__(self): super(AFMove, self).__init__() self.ai_opts: AIOptions = AIOptions.NONE self.pos_constraint: PositionConstraint = PositionConstraint.NONE self.unknown_4: int = 0 self.unknown_5: int = 0 self.unknown_6: int = 0 self.unknown_7: int = 0 self.unknown_8: int = 0 self.unknown_9: int = 0 self.unknown_10: int = 0 self.unknown_11: int = 0 self.next_animation_id: int = 0 self.category: MoveCategory = MoveCategory.MISCELLANEOUS self.unknown_14: int = 0 self.scrap_amount: int = 0 self.successor_id: int = 0 self.damage_amount: int = 0 self.collision_opts: CollisionOpts = CollisionOpts.NONE self.extra_string_selector: int = 0 self.points: int = 0 self.move_string: str = "" self.enemy_string: str = "" @staticmethod def get_name(index: int): if index in AF_ANIMATION_NAMES: return AF_ANIMATION_NAMES[index] return None def read(self, parser): super(AFMove, self).read(parser) self.ai_opts = AIOptions(parser.get_uint16()) self.pos_constraint = PositionConstraint(parser.get_uint16()) self.unknown_4 = parser.get_uint8() self.unknown_5 = parser.get_uint8() self.unknown_6 = parser.get_uint8() self.unknown_7 = parser.get_uint8() self.unknown_8 = parser.get_uint8() self.unknown_9 = parser.get_uint8() self.unknown_10 = parser.get_uint8() self.unknown_11 = parser.get_uint8() self.next_animation_id = parser.get_uint8() self.category = MoveCategory(parser.get_uint8()) self.unknown_14 = parser.get_uint8() self.scrap_amount = parser.get_uint8() self.successor_id = parser.get_uint8() self.damage_amount = parser.get_uint8() self.collision_opts = CollisionOpts(parser.get_uint8()) self.extra_string_selector = parser.get_uint8() self.points = parser.get_uint8() self.move_string = parser.get_null_padded_str(21) self.enemy_string = parser.get_var_str(size_includes_zero=True) return self def write(self, parser): super(AFMove, self).write(parser) parser.put_uint16(self.ai_opts.value) parser.put_uint16(self.pos_constraint.value) parser.put_uint8(self.unknown_4) parser.put_uint8(self.unknown_5) parser.put_uint8(self.unknown_6) parser.put_uint8(self.unknown_7) parser.put_uint8(self.unknown_8) parser.put_uint8(self.unknown_9) parser.put_uint8(self.unknown_10) parser.put_uint8(self.unknown_11) parser.put_uint8(self.next_animation_id) parser.put_uint8(self.category.value) parser.put_uint8(self.unknown_14) parser.put_uint8(self.scrap_amount) parser.put_uint8(self.successor_id) parser.put_uint8(self.damage_amount) parser.put_uint8(self.collision_opts.value) parser.put_uint8(self.extra_string_selector) parser.put_uint8(self.points) parser.put_null_padded_str(self.move_string, 21) parser.put_var_str(self.enemy_string, size_includes_zero=True) def serialize(self): return { **super(AFMove, self).serialize(), **{ "ai_opts": self.ai_opts.value, "pos_constraint": self.pos_constraint.value, "unknown_4": self.unknown_4, "unknown_5": self.unknown_5, "unknown_6": self.unknown_6, "unknown_7": self.unknown_7, "unknown_8": self.unknown_8, "unknown_9": self.unknown_9, "unknown_10": self.unknown_10, "unknown_11": self.unknown_11, "next_animation_id": self.next_animation_id, "category": self.category.value, "unknown_14": self.unknown_14, "scrap_amount": self.scrap_amount, "successor_id": self.successor_id, "damage_amount": self.damage_amount, "collision_opts": self.collision_opts.value, "extra_string_selector": self.extra_string_selector, "points": self.points, "move_string": self.move_string, "enemy_string": self.enemy_string, }, } def unserialize(self, data: dict): super(AFMove, self).unserialize(data) self.ai_opts = AIOptions(data["ai_opts"]) self.pos_constraint = PositionConstraint(data["pos_constraint"]) self.unknown_4 = data["unknown_4"] self.unknown_5 = data["unknown_5"] self.unknown_6 = data["unknown_6"] self.unknown_7 = data["unknown_7"] self.unknown_8 = data["unknown_8"] self.unknown_9 = data["unknown_9"] self.unknown_10 = data["unknown_10"] self.unknown_11 = data["unknown_11"] self.next_animation_id = data["next_animation_id"] self.category = MoveCategory(data["category"]) self.unknown_14 = data["unknown_14"] self.scrap_amount = data["scrap_amount"] self.successor_id = data["successor_id"] self.damage_amount = data["damage_amount"] self.collision_opts = CollisionOpts(data["collision_opts"]) self.extra_string_selector = data["extra_string_selector"] self.points = data["points"] self.move_string = data["move_string"] self.enemy_string = data["enemy_string"] return self
class BKFile(Entrypoint): ANIMATION_MAX_NUMBER = 50 __slots__ = ( "file_id", "unknown_a", "background_width", "background_height", "background_image", "animations", "sound_table", "palettes", ) schema = Dict( { "file_id": UInt32, "unknown_a": UInt8, "background_width": UInt16, "background_height": UInt16, "background_image": List(UInt8), "animations": Dict(extra=(Str(pattern=r"^[0-9]+$"), BKAnimation.schema)), "sound_table": List(UInt8, maxlen=30, minlen=30), "palettes": List(PaletteMapping.schema), } ) def __init__(self): self.file_id = 0 self.unknown_a = 0 self.background_width = 0 self.background_height = 0 self.animations: typing.Dict[int, BKAnimation] = {} self.palettes: typing.List[PaletteMapping] = [] self.sound_table: typing.List[int] = [] self.background_image: EncodedImage = [] def serialize(self): return { "file_id": self.file_id, "unknown_a": self.unknown_a, "background_width": self.background_width, "background_height": self.background_height, "background_image": self.background_image, "animations": {k: v.serialize() for k, v in self.animations.items()}, "palettes": [palette.serialize() for palette in self.palettes], "sound_table": self.sound_table, } def unserialize(self, data): self.file_id = data["file_id"] self.unknown_a = data["unknown_a"] self.background_width = data["background_width"] self.background_height = data["background_height"] self.background_image = data["background_image"] self.sound_table = data["sound_table"] self.palettes = [PaletteMapping().unserialize(v) for v in data["palettes"]] self.animations = { int(k): BKAnimation().unserialize(v) for k, v in data["animations"].items() } return self def read(self, parser): self.file_id = parser.get_uint32() self.unknown_a = parser.get_uint8() self.background_width = parser.get_uint16() self.background_height = parser.get_uint16() # Read all animations (up to max ANIMATION_MAX_NUMBER) while True: parser.get_uint32() # Skip anim_no = parser.get_uint8() if anim_no >= self.ANIMATION_MAX_NUMBER: break self.animations[anim_no] = BKAnimation().read(parser) # Read the raw Background image (VGA palette format) background_size = self.background_height * self.background_width self.background_image = [parser.get_uint8() for _ in range(background_size)] # Read up all available color palettes palette_count = parser.get_uint8() self.palettes = [PaletteMapping().read(parser) for _ in range(palette_count)] # Get sound mappings self.sound_table = [parser.get_uint8() for _ in range(30)] return self def write(self, parser): parser.put_uint32(self.file_id) parser.put_uint8(self.unknown_a) parser.put_uint16(self.background_width) parser.put_uint16(self.background_height) for key, ani in self.animations.items(): # Write animation to binary buffer so that # we can tell its length buf = io.BytesIO() ani.write(BinaryParser(buf)) ani_data = buf.getvalue() # Write offset of next animation, then ID, # then the animation blob. Add +5 to offset to account # for the next offset and ID. offset = parser.get_pos() + len(ani_data) + 5 parser.put_uint32(offset) parser.put_uint8(key) parser.put_bytes(ani_data) buf.close() # Write ending of the animations block parser.put_uint32(parser.get_pos()) parser.put_uint8(self.ANIMATION_MAX_NUMBER + 1) for pixel in self.background_image: parser.put_uint8(pixel) parser.put_uint8(len(self.palettes)) for pal in self.palettes: pal.write(parser) for sound in self.sound_table: parser.put_uint8(sound) def save_background(self, filename: str): save_png( generate_png( self.background_image, self.background_width, self.background_height, self.palettes[0].colors, ), filename, )
class AFFile(Entrypoint): MOVE_MAX_NUMBER = 70 __slots__ = ( "file_id", "exec_window", "endurance", "unknown_b", "health", "forward_speed", "reverse_speed", "jump_speed", "fall_speed", "unknown_c", "unknown_d", "sound_table", "moves", ) schema = Dict( { "file_id": UInt16, "exec_window": UInt16, "endurance": UInt32, "unknown_b": UInt8, "health": UInt16, "forward_speed": Int32, "reverse_speed": Int32, "jump_speed": Int32, "fall_speed": Int32, "unknown_c": UInt8, "unknown_d": UInt8, "sound_table": List(UInt8, maxlen=30, minlen=30), "moves": Dict(extra=(Str(pattern=r"^[0-9]+$"), AFMove.schema)), } ) def __init__(self): self.file_id: int = 0 self.exec_window: int = 0 self.endurance: int = 0 self.unknown_b: int = 0 self.health: int = 0 self.forward_speed: int = 0 self.reverse_speed: int = 0 self.jump_speed: int = 0 self.fall_speed: int = 0 self.unknown_c: int = 0 self.unknown_d: int = 0 self.moves: typing.Dict[int, AFMove] = {} self.sound_table: typing.List[int] = [] def serialize(self): return { "file_id": self.file_id, "exec_window": self.exec_window, "endurance": self.endurance, "unknown_b": self.unknown_b, "health": self.health, "forward_speed": self.forward_speed, "reverse_speed": self.reverse_speed, "jump_speed": self.jump_speed, "fall_speed": self.fall_speed, "unknown_c": self.unknown_c, "unknown_d": self.unknown_d, "moves": {k: v.serialize() for k, v in self.moves.items()}, "sound_table": self.sound_table, } def unserialize(self, data): self.file_id = data["file_id"] self.exec_window = data["exec_window"] self.endurance = data["endurance"] self.unknown_b = data["unknown_b"] self.health = data["health"] self.forward_speed = data["forward_speed"] self.reverse_speed = data["reverse_speed"] self.jump_speed = data["jump_speed"] self.fall_speed = data["fall_speed"] self.unknown_c = data["unknown_c"] self.unknown_d = data["unknown_d"] self.moves = {int(k): AFMove().unserialize(v) for k, v in data["moves"].items()} self.sound_table = data["sound_table"] return self def read(self, parser): self.file_id = parser.get_uint16() self.exec_window = parser.get_uint16() self.endurance = parser.get_uint32() self.unknown_b = parser.get_uint8() self.health = parser.get_uint16() self.forward_speed = parser.get_int32() self.reverse_speed = parser.get_int32() self.jump_speed = parser.get_int32() self.fall_speed = parser.get_int32() self.unknown_c = parser.get_uint8() self.unknown_d = parser.get_uint8() # Read all animations (up to max MOVE_MAX_NUMBER) while True: move_no = parser.get_uint8() if move_no >= self.MOVE_MAX_NUMBER: break self.moves[move_no] = AFMove().read(parser) # Find missing image data by index index_table: typing.Dict[int, Sprite] = {} for key, m in self.moves.items(): for idx, sprite in enumerate(m.sprites): if sprite.missing: if sprite.index in index_table: sprite.image = index_table[sprite.index].image else: index_table[sprite.index] = sprite # Read sound table for m in range(0, 30): sound = parser.get_uint8() self.sound_table.append(sound) return self def write(self, parser): parser.put_uint16(self.file_id) parser.put_uint16(self.exec_window) parser.put_uint32(self.endurance) parser.put_uint8(self.unknown_b) parser.put_uint16(self.health) parser.put_int32(self.forward_speed) parser.put_int32(self.reverse_speed) parser.put_int32(self.jump_speed) parser.put_int32(self.fall_speed) parser.put_uint8(self.unknown_c) parser.put_uint8(self.unknown_d) # Write moves for key, move in self.moves.items(): parser.put_uint8(key) move.write(parser) # Mark the end of moves parser.put_uint8(250) # Write sounds for sound in self.sound_table: parser.put_uint8(sound) @property def real_endurance(self): return self.endurance / 256.0 @real_endurance.setter def real_endurance(self, value): self.endurance = int(value * 256.0) @property def real_forward_speed(self): return self.forward_speed / 256.0 @real_forward_speed.setter def real_forward_speed(self, value): self.forward_speed = int(value * 256.0) @property def real_reverse_speed(self): return self.reverse_speed / 256.0 @real_reverse_speed.setter def real_reverse_speed(self, value): self.reverse_speed = int(value * 256.0) @property def real_jump_speed(self): return self.jump_speed / 256.0 @real_jump_speed.setter def real_jump_speed(self, value): self.jump_speed = int(value * 256.0) @property def real_fall_speed(self): return self.fall_speed / 256.0 @real_fall_speed.setter def real_fall_speed(self, value): self.fall_speed = int(value * 256.0)