# A representation of a Neopets::CustomPets viewer data response, translated # to DTI's database models! class Pet::ModelingSnapshot def initialize(viewer_data_hash) @custom_pet = viewer_data_hash[:custom_pet] @object_info_registry = viewer_data_hash[:object_info_registry] @object_asset_registry = viewer_data_hash[:object_asset_registry] end def pet_type @pet_type ||= begin raise Pet::UnexpectedDataFormat unless @custom_pet[:species_id] raise Pet::UnexpectedDataFormat unless @custom_pet[:color_id] raise Pet::UnexpectedDataFormat unless @custom_pet[:body_id] @custom_pet => {species_id:, color_id:} PetType.find_or_initialize_by(species_id:, color_id:).tap do |pet_type| # Apply the pet's body ID to the pet type, unless it's wearing an alt # style, in which case ignore it, because it's the *alt style*'s body ID. # (This can theoretically cause a problem saving a new pet type when # there's an alt style too!) pet_type.body_id = @custom_pet[:body_id] unless @custom_pet[:alt_style] if pet_type.body_id.nil? raise Pet::UnexpectedDataFormat, "can't process alt style on first occurrence of pet type" end # Try using this pet for the pet type's thumbnail, but don't worry # if it fails. begin pet_type.consider_pet_image(@custom_pet[:name]) rescue => error Rails.logger.warn "Failed to load pet image: #{error.full_message}" end end end end def pet_state @pet_state ||= begin swf_asset_ids = biology_assets.map(&:remote_id) pet_type.pet_states.find_or_initialize_by(swf_asset_ids:).tap do |pet_state| pet_state.swf_assets = biology_assets end end end def alt_style @alt_style ||= begin return nil unless @custom_pet[:alt_style] raise Pet::UnexpectedDataFormat unless @custom_pet[:alt_color] id = @custom_pet[:alt_style].to_i AltStyle.find_or_initialize_by(id:).tap do |alt_style| alt_style.assign_attributes( color_id: @custom_pet[:alt_color].to_i, species_id: @custom_pet[:species_id].to_i, body_id: @custom_pet[:body_id].to_i, swf_assets: alt_style_assets, ) end end end def items @items ||= @object_info_registry.map do |id, item_data| Item.find_or_initialize_by(id:).tap do |item| item.add_origin_registry_info item_data item.swf_assets = item_assets_for id end end end private def biology_assets @biology_assets ||= begin biology = @custom_pet[:alt_style].present? ? @custom_pet[:original_biology] : @custom_pet[:biology_by_zone] assets_from_biology(biology) end end def item_assets_for(item_id) all_infos = @object_asset_registry.values infos = all_infos.select { |a| a[:obj_info_id].to_i == item_id.to_i } infos.map do |asset_data| SwfAsset.from_object_data(@custom_pet[:body_id], asset_data) end end def alt_style_assets raise Pet::UnexpectedDataFormat if @custom_pet[:biology_by_zone].empty? @alt_style_assets ||= assets_from_biology(@custom_pet[:biology_by_zone]) end def assets_from_biology(biology) raise Pet::UnexpectedDataFormat if biology.empty? body_id = @custom_pet[:body_id].to_i biology.values.map { |b| SwfAsset.from_biology_data(body_id, b) } end end