From 87782767f8323782f5a020deca7518e9738aeb04 Mon Sep 17 00:00:00 2001 From: Emi Matchu Date: Tue, 27 Feb 2024 16:11:06 -0800 Subject: [PATCH] Filter search in wardrobe-2020 by alt styles! Yay, we finally added it, the part where we include the appearance data for the items based on both the species/color and the alt style! Now, switching to Faerie Acara correctly filters the search only to items that would fit (I think literally just only body_id=0 items right now, but we're not banking on that!) --- app/controllers/items_controller.rb | 13 +++++++++---- app/models/alt_style.rb | 5 +++++ app/models/item.rb | 28 ++++++++++++++++++++++++++++ app/models/pet_type.rb | 27 +++------------------------ 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/app/controllers/items_controller.rb b/app/controllers/items_controller.rb index 19ba6b64..955e8f30 100644 --- a/app/controllers/items_controller.rb +++ b/app/controllers/items_controller.rb @@ -121,11 +121,16 @@ class ItemsController < ApplicationController def load_appearances appearance_params = params[:with_appearances_for] return {} if appearance_params.blank? - raise NotImplementedError if appearance_params[:alt_style_id].present? + + if appearance_params[:alt_style_id].present? + target = Item::Search::Query.load_alt_style_by_id( + appearance_params[:alt_style_id]) + else + target = Item::Search::Query.load_pet_type_by_color_and_species( + appearance_params[:color_id], appearance_params[:species_id]) + end - pet_type = Item::Search::Query.load_pet_type_by_color_and_species( - appearance_params[:color_id], appearance_params[:species_id]) - pet_type.appearances_for(@items.map(&:id), swf_asset_includes: [:zone]) + target.appearances_for(@items.map(&:id), swf_asset_includes: [:zone]) end def search_error(e) diff --git a/app/models/alt_style.rb b/app/models/alt_style.rb index d437bd9b..15e43810 100644 --- a/app/models/alt_style.rb +++ b/app/models/alt_style.rb @@ -49,6 +49,11 @@ class AltStyle < ApplicationRecord swf_asset.image_url end + # Given a list of item IDs, return how they look on this alt style. + def appearances_for(item_ids, ...) + Item.appearances_for(item_ids, self, ...) + end + def biology=(biology) # TODO: This is very similar to what `PetState` does, but like… much much # more compact? Idk if I'm missing something, or if I was just that much diff --git a/app/models/item.rb b/app/models/item.rb index c0f4bf7a..1587ca21 100644 --- a/app/models/item.rb +++ b/app/models/item.rb @@ -495,6 +495,34 @@ class Item < ApplicationRecord end end + # Given a list of item IDs, return how they look on the given target (either + # a pet type or an alt style). + def self.appearances_for(item_ids, target, swf_asset_includes: []) + # First, load all the relationships for these items that also fit this + # body. + relationships = ParentSwfAssetRelationship. + includes(swf_asset: swf_asset_includes). + where(parent_type: "Item", parent_id: item_ids). + where(swf_asset: {body_id: [target.body_id, 0]}) + + pet_type_body = Appearance::Body.new(target.body_id, target.species) + all_pets_body = Appearance::Body.new(0, nil) + + # Then, convert this into a hash from item ID to SWF assets. + assets_by_item_id = relationships.group_by(&:parent_id). + transform_values { |rels| rels.map(&:swf_asset) } + + # Finally, for each item, return an appearance—even if it's empty! + item_ids.to_h do |item_id| + assets = assets_by_item_id.fetch(item_id, []) + + fits_all_pets = assets.present? && assets.all? { |a| a.body_id == 0 } + body = fits_all_pets ? all_pets_body : pet_type_body + + [item_id, Appearance.new(body, assets)] + end + end + def self.all_by_ids_or_children(ids, swf_assets) swf_asset_ids = [] swf_assets_by_id = {} diff --git a/app/models/pet_type.rb b/app/models/pet_type.rb index 49230af0..5138d267 100644 --- a/app/models/pet_type.rb +++ b/app/models/pet_type.rb @@ -169,30 +169,9 @@ class PetType < ApplicationRecord }.first end - def appearances_for(item_ids, swf_asset_includes: []) - # First, load all the relationships for these items that also fit this - # body. - relationships = ParentSwfAssetRelationship. - includes(swf_asset: swf_asset_includes). - where(parent_type: "Item", parent_id: item_ids). - where(swf_asset: {body_id: [body_id, 0]}) - - pet_type_body = Item::Appearance::Body.new(body_id, species) - all_pets_body = Item::Appearance::Body.new(0, nil) - - # Then, convert this into a hash from item ID to SWF assets. - assets_by_item_id = relationships.group_by(&:parent_id). - transform_values { |rels| rels.map(&:swf_asset) } - - # Finally, for each item, return an appearance—even if it's empty! - item_ids.to_h do |item_id| - assets = assets_by_item_id.fetch(item_id, []) - - fits_all_pets = assets.present? && assets.all? { |a| a.body_id == 0 } - body = fits_all_pets ? all_pets_body : pet_type_body - - [item_id, Item::Appearance.new(body, assets)] - end + # Given a list of item IDs, return how they look on this pet type. + def appearances_for(item_ids, ...) + Item.appearances_for(item_ids, self, ...) end def self.all_by_ids_or_children(ids, pet_states)