def parse_sw_json(data, owner, options): wizard_id = None parsed_runes = [] parsed_rune_crafts = [] parsed_artifacts = [] parsed_artifact_crafts = [] parsed_mons = [] parsed_inventory = {} parsed_monster_pieces = [] parsed_buildings = [] # Grab the friend if data.get('command') == 'VisitFriend': data = data['friend'] if 'wizard_info' in data: wizard_id = data['wizard_info'].get('wizard_id') building_list = data['building_list'] deco_list = data['deco_list'] inventory_info = data.get('inventory_info') # Optional unit_list = data['unit_list'] runes_info = data.get('runes') # Optional locked_mons = data.get('unit_lock_list') # Optional craft_info = data.get('rune_craft_item_list') # Optional artifact_info = data.get('artifacts') # Optional artifact_craft_info = data.get('artifact_crafts') # Optional # Buildings storage_building_id = None for building in building_list: if building: # Find which one is the storage building if building.get('building_master_id') == 25: storage_building_id = building.get('building_id') break for deco in deco_list: try: base_building = Building.objects.get(com2us_id=deco['master_id']) except Building.DoesNotExist: continue level = deco['level'] try: building_instance = BuildingInstance.objects.get( owner=owner, building=base_building) except BuildingInstance.DoesNotExist: building_instance = BuildingInstance(owner=owner, building=base_building) except BuildingInstance.MultipleObjectsReturned: # Should only be 1 ever - use the first and delete the others. building_instance = BuildingInstance.objects.filter( owner=owner, building=base_building).first() BuildingInstance.objects.filter( owner=owner, building=base_building).exclude( pk=building_instance.pk).delete() building_instance.level = level parsed_buildings.append(building_instance) # Inventory - essences and summoning pieces if inventory_info: for item in inventory_info: # Essence Inventory if item['item_master_type'] == GameItem.CATEGORY_ESSENCE: essence = inventory_essence_map.get(item['item_master_id']) quantity = item.get('item_quantity') if essence and quantity: parsed_inventory[essence] = quantity elif item['item_master_type'] == GameItem.CATEGORY_CRAFT_STUFF: craft = inventory_craft_map.get(item['item_master_id']) quantity = item.get('item_quantity') if craft and quantity: parsed_inventory[craft] = quantity elif item['item_master_type'] == GameItem.CATEGORY_MONSTER_PIECE: quantity = item.get('item_quantity') if quantity > 0: mon = get_monster_from_id(item['item_master_id']) if mon: parsed_monster_pieces.append( MonsterPiece( monster=mon, pieces=quantity, owner=owner, )) elif item[ 'item_master_type'] == GameItem.CATEGORY_MATERIAL_MONSTER: monster = inventory_enhance_monster_map.get( item['item_master_id']) quantity = item.get('item_quantity') if monster and quantity: parsed_inventory[monster] = quantity elif item['item_master_type'] == GameItem.CATEGORY_ARTIFACT_CRAFT: quantity = item.get('item_quantity') if quantity: parsed_inventory['conversion_stone'] = quantity # Extract Rune Inventory (unequipped runes) if runes_info: for rune_data in runes_info: rune = parse_rune_data(rune_data, owner) if rune: rune.owner = owner rune.assigned_to = None parsed_runes.append(rune) # Extract monsters for unit_info in unit_list: # Get base monster type com2us_id = unit_info.get('unit_id') monster_type_id = str(unit_info.get('unit_master_id')) mon = None if not options['clear_profile']: mon = MonsterInstance.objects.filter(com2us_id=com2us_id, owner=owner).first() if not mon: mon = MonsterInstance() is_new = True else: is_new = False mon.com2us_id = com2us_id # Base monster try: mon.monster = Monster.objects.get(com2us_id=monster_type_id) except Monster.DoesNotExist: # Unable to find a matching monster in the database - either crap data or brand new monster. Don't parse it. continue mon.stars = unit_info.get('class') mon.level = unit_info.get('unit_level') skills = unit_info.get('skills', []) if len(skills) >= 1: mon.skill_1_level = skills[0][1] if len(skills) >= 2: mon.skill_2_level = skills[1][1] if len(skills) >= 3: mon.skill_3_level = skills[2][1] if len(skills) >= 4: mon.skill_4_level = skills[3][1] try: created_date = get_current_timezone().localize(parse( unit_info.get('create_time')), is_dst=False) mon.created = created_date except (ValueError, TypeError): mon.created = None mon.owner = owner mon.in_storage = unit_info.get('building_id') == storage_building_id # Set priority levels if options['default_priority'] and is_new: mon.priority = options['default_priority'] if mon.monster.archetype == Monster.ARCHETYPE_MATERIAL: mon.fodder = True mon.priority = MonsterInstance.PRIORITY_DONE # Lock a monster if it's locked in game if options['lock_monsters']: mon.ignore_for_fusion = locked_mons is not None and mon.com2us_id in locked_mons # Equipped runes and artifacts equipped_runes = unit_info.get('runes') equipped_artifacts = unit_info.get('artifacts', []) # Check import options to determine if monster should be saved level_ignored = mon.stars < options['minimum_stars'] silver_ignored = options['ignore_silver'] and not mon.monster.can_awaken material_ignored = options[ 'ignore_material'] and mon.monster.archetype == Monster.ARCHETYPE_MATERIAL allow_due_to_runes = options['except_with_runes'] and ( len(equipped_runes) > 0 or len(equipped_artifacts) > 0) allow_due_to_ld = options[ 'except_light_and_dark'] and mon.monster.element in [ Monster.ELEMENT_DARK, Monster.ELEMENT_LIGHT ] and mon.monster.archetype != Monster.ARCHETYPE_MATERIAL allow_due_to_fusion = options[ 'except_fusion_ingredient'] and mon.monster.fusion_food should_be_skipped = any( [level_ignored, silver_ignored, material_ignored]) import_anyway = any( [allow_due_to_runes, allow_due_to_ld, allow_due_to_fusion]) if should_be_skipped and not import_anyway: continue # Set custom name if homunculus custom_name = unit_info.get('homunculus_name') if unit_info.get('homunculus') and custom_name: mon.custom_name = custom_name parsed_mons.append(mon) # Sometimes the runes are a dict or a list in the json. Convert to list. if isinstance(equipped_runes, dict): equipped_runes = equipped_runes.values() for rune_data in equipped_runes: rune = parse_rune_data(rune_data, owner) if rune: rune.owner = owner rune.assigned_to = mon parsed_runes.append(rune) for artifact_data in equipped_artifacts: artifact = parse_artifact_data(artifact_data, owner) if artifact: artifact.owner = owner artifact.assigned_to = mon parsed_artifacts.append(artifact) # Extract grindstones/enchant gems if craft_info: for craft_data in craft_info: craft = parse_rune_craft_data(craft_data, owner) if craft: craft.owner = owner parsed_rune_crafts.append(craft) # Extract artifact inventory if artifact_info: for artifact_data in artifact_info: artifact = parse_artifact_data(artifact_data, owner) if artifact: artifact.owner = owner artifact.assigned_to = None parsed_artifacts.append(artifact) if artifact_craft_info: for craft_data in artifact_craft_info: craft = parse_artifact_craft_data(craft_data, owner) if craft: craft.owner = owner parsed_artifact_crafts.append(craft) import_results = { 'wizard_id': wizard_id, 'monsters': parsed_mons, 'monster_pieces': parsed_monster_pieces, 'runes': parsed_runes, 'rune_crafts': parsed_rune_crafts, 'artifacts': parsed_artifacts, 'artifact_crafts': parsed_artifact_crafts, 'inventory': parsed_inventory, 'buildings': parsed_buildings, 'rta_assignments': data['world_arena_rune_equip_list'] } return import_results
def parse_sw_json(data, owner, options): wizard_id = None parsed_runes = {} parsed_rune_crafts = {} parsed_artifacts = {} parsed_artifact_crafts = {} parsed_mons = {} parsed_inventory = {} parsed_monster_shrine = {} parsed_monster_pieces = [] parsed_buildings = {} server_id_mapping = { None: None, 1: Summoner.SERVER_GLOBAL, 2: Summoner.SERVER_KOREA, 3: Summoner.SERVER_JAPAN, 4: Summoner.SERVER_CHINA, 5: Summoner.SERVER_ASIA, 6: Summoner.SERVER_EUROPE, } server_id = server_id_mapping[data.get('server_id', None)] # Grab the friend if data.get('command') == 'VisitFriend': data = data['friend'] if 'wizard_info' in data: wizard_id = data['wizard_info'].get('wizard_id') building_list = data['building_list'] deco_list = data['deco_list'] inventory_info = data.get('inventory_info') # Optional unit_list = data['unit_list'] runes_info = data.get('runes') # Optional locked_mons = data.get('unit_lock_list') # Optional craft_info = data.get('rune_craft_item_list') # Optional artifact_info = data.get('artifacts') # Optional artifact_craft_info = data.get('artifact_crafts') # Optional monster_shrine_info = data.get('unit_storage_list') # Optional # Buildings storage_building_id = None for building in building_list: if building: # Find which one is the storage building if building.get('building_master_id') == 25: storage_building_id = building.get('building_id') break for deco in deco_list: try: base_building = Building.objects.get(com2us_id=deco['master_id']) except Building.DoesNotExist: continue level = deco['level'] try: building_instance = BuildingInstance.objects.get( owner=owner, building=base_building) except BuildingInstance.DoesNotExist: building_instance = BuildingInstance(owner=owner, building=base_building) except BuildingInstance.MultipleObjectsReturned: # Should only be 1 ever - use the first and delete the others. building_instance = BuildingInstance.objects.filter( owner=owner, building=base_building).first() BuildingInstance.objects.filter( owner=owner, building=base_building).exclude( pk=building_instance.pk).delete() if building_instance.level != level: building_instance.level = level parsed_buildings[building_instance.pk] = { 'obj': building_instance, 'new': True, } else: parsed_buildings[building_instance.pk] = { 'obj': building_instance, 'new': False, } # Inventory - essences and summoning pieces if inventory_info: for item in inventory_info: # Essence Inventory if (item['item_master_type'] == GameItem.CATEGORY_ESSENCE or item['item_master_type'] == GameItem.CATEGORY_CRAFT_STUFF or item['item_master_type'] == GameItem.CATEGORY_MATERIAL_MONSTER or item['item_master_type'] == GameItem.CATEGORY_ARTIFACT_CRAFT): parsed_inventory[ item['item_master_id']] = item['item_quantity'] elif item['item_master_type'] == GameItem.CATEGORY_MONSTER_PIECE: quantity = item.get('item_quantity') if quantity > 0: mon = get_monster_from_id(item['item_master_id']) if mon: has_changed = False monster_piece, created = MonsterPiece.objects.get_or_create( owner=owner, monster=mon, defaults={ 'pieces': quantity, }) if not created and monster_piece.pieces != quantity: monster_piece.pieces = quantity has_changed = True parsed_monster_pieces.append({ 'obj': monster_piece, 'new': has_changed or created, }) if monster_shrine_info: for item in monster_shrine_info: parsed_monster_shrine[item['unit_master_id']] = item['quantity'] # Extract Rune Inventory (unequipped runes) if runes_info: for rune_data in runes_info: rune = parse_rune_data(rune_data, owner) if rune: parsed_runes[rune.pk] = rune # Extract monsters for unit_info in unit_list: # Get base monster type com2us_id = unit_info.get('unit_id') monster_type_id = str(unit_info.get('unit_master_id')) mon = None if not options['clear_profile']: mon = MonsterInstance.objects.filter(com2us_id=com2us_id, owner=owner).first() if not mon: mon = MonsterInstance() is_new = True else: is_new = False mon.com2us_id = com2us_id # Base monster try: temp_monster = Monster.objects.get(com2us_id=monster_type_id) except Monster.DoesNotExist: # Unable to find a matching monster in the database - either crap data or brand new monster. Don't parse it. continue # Equipped runes and artifacts equipped_runes = unit_info.get('runes') equipped_artifacts = unit_info.get('artifacts', []) # Sometimes the runes are a dict or a list in the json. Convert to list. if isinstance(equipped_runes, dict): equipped_runes = equipped_runes.values() mon_runes = [] for rune_data in equipped_runes: rune = parse_rune_data(rune_data, owner) if rune: parsed_runes[rune.pk] = rune mon_runes.append(rune) mon_artifacts = [] for artifact_data in equipped_artifacts: artifact = parse_artifact_data(artifact_data, owner) if artifact: parsed_artifacts[artifact.pk] = artifact mon_artifacts.append(artifact) skills = unit_info.get('skills', []) temp_skill_1_level = skills[0][1] if len(skills) >= 1 else None temp_skill_2_level = skills[1][1] if len(skills) >= 2 else None temp_skill_3_level = skills[2][1] if len(skills) >= 3 else None temp_skill_4_level = skills[3][1] if len(skills) >= 4 else None mon.monster = temp_monster mon.stars = unit_info.get('class') mon.level = unit_info.get('unit_level') # Lock a monster if it's locked in game if options['lock_monsters']: mon.ignore_for_fusion = locked_mons is not None and mon.com2us_id in locked_mons if temp_skill_1_level: mon.skill_1_level = temp_skill_1_level if temp_skill_2_level: mon.skill_2_level = temp_skill_2_level if temp_skill_3_level: mon.skill_3_level = temp_skill_3_level if temp_skill_4_level: mon.skill_4_level = temp_skill_4_level try: created_date = get_current_timezone().localize(parse( unit_info.get('create_time')), is_dst=False) mon.created = created_date except (ValueError, TypeError): mon.created = None mon.owner = owner mon.in_storage = unit_info.get('building_id') == storage_building_id # Set priority levels if options['default_priority'] and is_new: mon.priority = options['default_priority'] if mon.monster.archetype == Monster.ARCHETYPE_MATERIAL: mon.fodder = True mon.priority = MonsterInstance.PRIORITY_DONE # Check import options to determine if monster should be saved level_ignored = mon.stars < options['minimum_stars'] silver_ignored = options['ignore_silver'] and not mon.monster.can_awaken material_ignored = options[ 'ignore_material'] and mon.monster.archetype == Monster.ARCHETYPE_MATERIAL allow_due_to_runes = options['except_with_runes'] and ( len(equipped_runes) > 0 or len(equipped_artifacts) > 0) allow_due_to_ld = options[ 'except_light_and_dark'] and mon.monster.element in [ Monster.ELEMENT_DARK, Monster.ELEMENT_LIGHT ] and mon.monster.archetype != Monster.ARCHETYPE_MATERIAL allow_due_to_fusion = options[ 'except_fusion_ingredient'] and mon.monster.fusion_food should_be_skipped = any( [level_ignored, silver_ignored, material_ignored]) import_anyway = any( [allow_due_to_runes, allow_due_to_ld, allow_due_to_fusion]) if should_be_skipped and not import_anyway: continue # Set custom name if homunculus custom_name = unit_info.get('homunculus_name') if unit_info.get('homunculus') and custom_name: mon.custom_name = custom_name parsed_mons[mon.pk] = { "obj": mon, "runes": mon_runes, "artifacts": mon_artifacts } # Extract grindstones/enchant gems if craft_info: for craft_data in craft_info: craft, has_changed_or_new = parse_rune_craft_data( craft_data, owner) if craft: if has_changed_or_new: craft.owner = owner parsed_rune_crafts[craft.pk] = { 'obj': craft, 'new': has_changed_or_new } # Extract artifact inventory if artifact_info: for artifact_data in artifact_info: artifact = parse_artifact_data(artifact_data, owner) if artifact: parsed_artifacts[artifact.pk] = artifact if artifact_craft_info: for craft_data in artifact_craft_info: craft, has_changed_or_new = parse_artifact_craft_data( craft_data, owner) if craft: if has_changed_or_new: craft.owner = owner parsed_artifact_crafts[craft.pk] = { 'obj': craft, 'new': has_changed_or_new, } import_results = { 'wizard_id': wizard_id, 'server_id': server_id, 'monsters': parsed_mons, 'monster_pieces': parsed_monster_pieces, 'runes': parsed_runes, 'rune_crafts': parsed_rune_crafts, 'artifacts': parsed_artifacts, 'artifact_crafts': parsed_artifact_crafts, 'inventory': parsed_inventory, 'monster_shrine': parsed_monster_shrine, 'buildings': parsed_buildings, 'rta_assignments': data['world_arena_rune_equip_list'], 'rta_assignments_artifacts': data['world_arena_artifact_equip_list'], } return import_results
def parse_sw_json(data, owner, options): errors = [] wizard_id = None parsed_runes = [] parsed_rune_crafts = [] parsed_mons = [] parsed_inventory = {} parsed_monster_pieces = [] # Grab the friend if data.get('command') == 'VisitFriend': data = data['friend'] if 'wizard_info' in data: wizard_id = data['wizard_info'].get('wizard_id') building_list = data['building_list'] inventory_info = data.get('inventory_info') # Optional unit_list = data['unit_list'] runes_info = data.get('runes') # Optional locked_mons = data.get('unit_lock_list') # Optional craft_info = data.get('rune_craft_item_list') # Optional # Buildings storage_building_id = None for building in building_list: if building: # Find which one is the storage building if building.get('building_master_id') == 25: storage_building_id = building.get('building_id') break # Inventory - essences and summoning pieces if inventory_info: for item in inventory_info: # Essence Inventory if item['item_master_type'] == inventory_type_map['essences']: essence = inventory_essence_map.get(item['item_master_id']) quantity = item.get('item_quantity') if essence and quantity: parsed_inventory[essence] = quantity elif item['item_master_type'] == inventory_type_map['craft_stuff']: craft = inventory_craft_map.get(item['item_master_id']) quantity = item.get('item_quantity') if craft and quantity: parsed_inventory[craft] = quantity elif item['item_master_type'] == inventory_type_map['monster_piece']: quantity = item.get('item_quantity') if quantity > 0: try: mon = get_monster_from_id(item['item_master_id']) except ValueError as e: errors.append(e.message) else: if mon: parsed_monster_pieces.append(MonsterPiece( monster=mon, pieces=quantity, owner=owner, uncommitted=True, )) # Extract Rune Inventory (unequipped runes) if runes_info: for rune_data in runes_info: rune = parse_rune_data(rune_data, owner) if rune: rune.owner = owner rune.assigned_to = None parsed_runes.append(rune) else: errors.append('Unable to parse rune in inventory with this data: ' + str(rune_data)) # Extract monsters for unit_info in unit_list: # Get base monster type com2us_id = unit_info.get('unit_id') monster_type_id = str(unit_info.get('unit_master_id')) mon = None if not options['clear_profile']: mon = MonsterInstance.objects.filter(com2us_id=com2us_id, owner=owner).first() if not mon: mon = MonsterInstance() is_new = True else: is_new = False # Make sure it's saved as a new instance and marked as an import mon.pk = None mon.uncommitted = True mon.com2us_id = com2us_id # Base monster try: mon.monster = Monster.objects.get(com2us_id=monster_type_id) except Monster.DoesNotExist: errors.append('Unable to parse monster data. Monster type: ' + str(unit_info.get('unit_master_id')) + '. Monster ID: ' + str(unit_info.get('unit_id'))) continue mon.stars = unit_info.get('class') mon.level = unit_info.get('unit_level') skills = unit_info.get('skills', []) if len(skills) >= 1: mon.skill_1_level = skills[0][1] if len(skills) >= 2: mon.skill_2_level = skills[1][1] if len(skills) >= 3: mon.skill_3_level = skills[2][1] if len(skills) >= 4: mon.skill_4_level = skills[3][1] try: created_date = get_current_timezone().localize(parse(unit_info.get('create_time')), is_dst=False) mon.created = created_date except (ValueError, TypeError): mon.created = None mon.owner = owner mon.in_storage = unit_info.get('building_id') == storage_building_id # Set priority levels if options['default_priority'] and is_new: mon.priority = options['default_priority'] if mon.monster.archetype == Monster.TYPE_MATERIAL: mon.fodder = True mon.priority = MonsterInstance.PRIORITY_DONE # Lock a monster if it's locked in game mon.ignore_for_fusion = locked_mons and mon.com2us_id in locked_mons # Equipped runes equipped_runes = unit_info.get('runes') # Check import options to determine if monster should be saved level_ignored = mon.stars < options['minimum_stars'] silver_ignored = options['ignore_silver'] and not mon.monster.can_awaken material_ignored = options['ignore_material'] and mon.monster.archetype == Monster.TYPE_MATERIAL allow_due_to_runes = options['except_with_runes'] and len(equipped_runes) > 0 allow_due_to_ld = options['except_light_and_dark'] and mon.monster.element in [Monster.ELEMENT_DARK, Monster.ELEMENT_LIGHT] and mon.monster.archetype != Monster.TYPE_MATERIAL if (level_ignored or silver_ignored or material_ignored) and not (allow_due_to_runes or allow_due_to_ld): continue parsed_mons.append(mon) # Sometimes the runes are a dict or a list in the json. Convert to list. if isinstance(equipped_runes, dict): equipped_runes = equipped_runes.values() for rune_data in equipped_runes: rune = parse_rune_data(rune_data, owner) if rune: rune.owner = owner rune.assigned_to = mon parsed_runes.append(rune) else: errors.append('Unable to parse rune assigned to ' + str(mon)) # Extract grindstones/enchant gems if craft_info: for craft_data in craft_info: craft = parse_rune_craft_data(craft_data, owner) if craft: craft.owner = owner parsed_rune_crafts.append(craft) else: errors.append('Unable to parse gem/grindstone in inventory with this data: ' + str(craft_data)) import_results = { 'errors': errors, 'wizard_id': wizard_id, 'monsters': parsed_mons, 'monster_pieces': parsed_monster_pieces, 'runes': parsed_runes, 'crafts': parsed_rune_crafts, 'inventory': parsed_inventory, } return import_results
def handle(self, *args, **kwargs): # TODO: Add whole `herders` copy, not only Monsters, Runes & Artifacts # TODO: DEFAULT / RTA BUILDS if not settings.DEBUG: self.stdout.write( self.style.ERROR('Command used outside DEBUG Mode')) return # timestamp, so there's no problem with dupe account logins ACC_LOGIN = f'propagated_$ID$_{int(time.time())}' # some sort of PASSWD generator, we won't use it anyway PASSWD = ''.join( random.choice(string.ascii_letters + string.digits + string.punctuation) for _ in range(24)) monster_fields = [ 'pk', 'owner_id', 'monster_id', 'com2us_id', 'created', 'stars', 'level', 'skill_1_level', 'skill_2_level', 'skill_3_level', 'skill_4_level', 'fodder', 'in_storage', 'ignore_for_fusion', 'priority', 'notes', 'custom_name', ] rune_fields = [ 'type', 'owner_id', 'com2us_id', 'assigned_to_id', 'marked_for_sale', 'notes', 'main_stat', 'main_stat_value', 'innate_stat', 'innate_stat_value', 'stars', 'level', 'slot', 'quality', 'original_quality', 'ancient', 'value', 'substats', 'substat_values', 'substats_enchanted', 'substats_grind_value', 'has_hp', 'has_atk', 'has_def', 'has_crit_rate', 'has_crit_dmg', 'has_speed', 'has_resist', 'has_accuracy', 'efficiency', 'max_efficiency', 'substat_upgrades_remaining', 'has_grind', 'has_gem', ] artifact_fields = [ 'owner_id', 'com2us_id', 'assigned_to_id', 'level', 'original_quality', 'main_stat', 'main_stat_value', 'effects', 'effects_value', 'effects_upgrade_count', 'effects_reroll_count', 'efficiency', 'max_efficiency', 'slot', 'element', 'archetype', 'quality' ] start = time.time() acc_quantity = kwargs['accounts_quantity'] self.stdout.write( self.style.SUCCESS( f'Starting data duplication process for {acc_quantity} account(s)!' )) owner = Summoner.objects.first() if not owner: self.stdout.write( self.style.ERROR( "No Summoner records in database, can't duplicate empty data" )) return monsters = MonsterInstance.objects.filter(owner=owner).values( *monster_fields) runes = RuneInstance.objects.filter(owner=owner).values(*rune_fields) artifacts = ArtifactInstance.objects.filter(owner=owner).values( *artifact_fields) self.stdout.write(self.style.SUCCESS(f'Duplicating per account:')) self.stdout.write(self.style.WARNING(f'- Monsters: {len(monsters)}')) self.stdout.write(self.style.WARNING(f'- Runes: {len(runes)}')) self.stdout.write(self.style.WARNING(f'- Artifacts: {len(artifacts)}')) monster_pks = {m.pop('pk'): m['com2us_id'] for m in monsters} for iter in range(acc_quantity): iter_objs = { 'monsters': [], 'runes': [], 'artifacts': [], } login = ACC_LOGIN.replace('$ID$', str(iter)) iter_start = time.time() with transaction.atomic(): user = User.objects.create_user(login, login + '@gmail.com', PASSWD) summoner = Summoner.objects.create(user=user, com2us_id=owner.com2us_id) for mon in monsters: mon_obj = MonsterInstance(**mon) mon_obj.owner = summoner iter_objs['monsters'].append(mon_obj) iter_mons = { m.com2us_id: m for m in MonsterInstance.objects.bulk_create( iter_objs['monsters']) } for rune in runes: rune_obj = RuneInstance(**rune) rune_obj.owner = summoner rune_obj.assigned_to = iter_mons[monster_pks[rune[ 'assigned_to_id']]] if rune['assigned_to_id'] else None iter_objs['runes'].append(rune_obj) for artifact in artifacts: artifact_obj = ArtifactInstance(**artifact) artifact_obj.owner = summoner artifact_obj.assigned_to = iter_mons[monster_pks[ artifact['assigned_to_id']]] if artifact[ 'assigned_to_id'] else None iter_objs['artifacts'].append(artifact_obj) RuneInstance.objects.bulk_create(iter_objs['runes']) ArtifactInstance.objects.bulk_create(iter_objs['artifacts']) self.stdout.write( self.style.WARNING( f"[{iter + 1}] This iteration took {round(time.time() - iter_start, 2)} seconds ({round(time.time() - start, 2)} in total)!" )) self.stdout.write( self.style.SUCCESS('Done creating accounts and duplicating data.'))
def parse_sw_json(data, owner, options): errors = [] wizard_id = None parsed_runes = [] parsed_rune_crafts = [] parsed_mons = [] parsed_inventory = {} parsed_monster_pieces = [] # Grab the friend if data.get('command') == 'VisitFriend': data = data['friend'] if 'wizard_info' in data: wizard_id = data['wizard_info'].get('wizard_id') building_list = data['building_list'] inventory_info = data.get('inventory_info') # Optional unit_list = data['unit_list'] runes_info = data.get('runes') # Optional locked_mons = data.get('unit_lock_list') # Optional craft_info = data.get('rune_craft_item_list') # Optional # Buildings storage_building_id = None for building in building_list: if building: # Find which one is the storage building if building.get('building_master_id') == 25: storage_building_id = building.get('building_id') break # Inventory - essences and summoning pieces if inventory_info: for item in inventory_info: # Essence Inventory if item['item_master_type'] == inventory_type_map['essences']: essence = inventory_essence_map.get(item['item_master_id']) quantity = item.get('item_quantity') if essence and quantity: parsed_inventory[essence] = quantity elif item['item_master_type'] == inventory_type_map['craft_stuff']: craft = inventory_craft_map.get(item['item_master_id']) quantity = item.get('item_quantity') if craft and quantity: parsed_inventory[craft] = quantity elif item['item_master_type'] == inventory_type_map['monster_piece']: quantity = item.get('item_quantity') if quantity > 0: try: mon = get_monster_from_id(item['item_master_id']) except ValueError as e: errors.append(e.message) else: if mon: parsed_monster_pieces.append(MonsterPiece( monster=mon, pieces=quantity, owner=owner, uncommitted=True, )) # Extract Rune Inventory (unequipped runes) if runes_info: for rune_data in runes_info: rune = parse_rune_data(rune_data, owner) if rune: rune.owner = owner rune.assigned_to = None parsed_runes.append(rune) else: errors.append('Unable to parse rune in inventory with this data: ' + str(rune_data)) # Extract monsters for unit_info in unit_list: # Get base monster type com2us_id = unit_info.get('unit_id') monster_type_id = str(unit_info.get('unit_master_id')) mon = None if not options['clear_profile']: mon = MonsterInstance.objects.filter(com2us_id=com2us_id, owner=owner).first() if not mon: mon = MonsterInstance() is_new = True else: is_new = False # Make sure it's saved as a new instance and marked as an import mon.pk = None mon.uncommitted = True mon.com2us_id = com2us_id # Base monster try: mon.monster = Monster.objects.get(com2us_id=monster_type_id) except Monster.DoesNotExist: errors.append('Unable to parse monster data. Monster type: ' + str(unit_info.get('unit_master_id')) + '. Monster ID: ' + str(unit_info.get('unit_id'))) continue mon.stars = unit_info.get('class') mon.level = unit_info.get('unit_level') skills = unit_info.get('skills', []) if len(skills) >= 1: mon.skill_1_level = skills[0][1] if len(skills) >= 2: mon.skill_2_level = skills[1][1] if len(skills) >= 3: mon.skill_3_level = skills[2][1] if len(skills) >= 4: mon.skill_4_level = skills[3][1] try: created_date = get_current_timezone().localize(parse(unit_info.get('create_time')), is_dst=False) mon.created = created_date except (ValueError, TypeError): mon.created = None mon.owner = owner mon.in_storage = unit_info.get('building_id') == storage_building_id # Set priority levels if options['default_priority'] and is_new: mon.priority = options['default_priority'] if mon.monster.archetype == Monster.TYPE_MATERIAL: mon.fodder = True mon.priority = MonsterInstance.PRIORITY_DONE # Set ignore for fusion if requested if options['ignore_fusion'] and mon.monster.fusion_food and (locked_mons and mon.com2us_id in locked_mons): mon.ignore_for_fusion = True # Equipped runes equipped_runes = unit_info.get('runes') # Check import options to determine if monster should be saved level_ignored = mon.stars < options['minimum_stars'] silver_ignored = options['ignore_silver'] and not mon.monster.can_awaken material_ignored = options['ignore_material'] and mon.monster.archetype == Monster.TYPE_MATERIAL allow_due_to_runes = options['except_with_runes'] and len(equipped_runes) > 0 allow_due_to_ld = options['except_light_and_dark'] and mon.monster.element in [Monster.ELEMENT_DARK, Monster.ELEMENT_LIGHT] and mon.monster.archetype != Monster.TYPE_MATERIAL if (level_ignored or silver_ignored or material_ignored) and not (allow_due_to_runes or allow_due_to_ld): continue parsed_mons.append(mon) # Sometimes the runes are a dict or a list in the json. Convert to list. if isinstance(equipped_runes, dict): equipped_runes = equipped_runes.values() for rune_data in equipped_runes: rune = parse_rune_data(rune_data, owner) if rune: rune.owner = owner rune.assigned_to = mon parsed_runes.append(rune) else: errors.append('Unable to parse rune assigned to ' + str(mon)) # Extract grindstones/enchant gems if craft_info: for craft_data in craft_info: craft = parse_rune_craft_data(craft_data, owner) if craft: craft.owner = owner parsed_rune_crafts.append(craft) else: errors.append('Unable to parse gem/grindstone in inventory with this data: ' + str(craft_data)) import_results = { 'errors': errors, 'wizard_id': wizard_id, 'monsters': parsed_mons, 'monster_pieces': parsed_monster_pieces, 'runes': parsed_runes, 'crafts': parsed_rune_crafts, 'inventory': parsed_inventory, } return import_results