diff --git a/app/controllers/item_zone_sets_controller.rb b/app/controllers/item_zone_sets_controller.rb index cbfcdabb..92282c02 100644 --- a/app/controllers/item_zone_sets_controller.rb +++ b/app/controllers/item_zone_sets_controller.rb @@ -1,7 +1,5 @@ class ItemZoneSetsController < ApplicationController - caches_page :index - def index - render :json => Zone::ItemZoneSets.keys.sort.as_json + render :json => Zone.all_plain_labels end end diff --git a/app/controllers/items_controller.rb b/app/controllers/items_controller.rb index 9a6e2908..519e096c 100644 --- a/app/controllers/items_controller.rb +++ b/app/controllers/items_controller.rb @@ -45,6 +45,15 @@ class ItemsController < ApplicationController respond_to do |format| format.html do + unless localized_fragment_exist?("items/#{@item.id} info") + @occupied_zones = @item.occupied_zones( + :scope => Zone.includes_translations.alphabetical + ) + @restricted_zones = @item.restricted_zones( + :scope => Zone.includes_translations.alphabetical + ) + end + unless localized_fragment_exist?("items/#{@item.id} contributors") @contributors_with_counts = @item.contributors_with_counts end diff --git a/app/controllers/swf_assets_controller.rb b/app/controllers/swf_assets_controller.rb index 8ce7c9f3..0af82690 100644 --- a/app/controllers/swf_assets_controller.rb +++ b/app/controllers/swf_assets_controller.rb @@ -2,7 +2,7 @@ class SwfAssetsController < ApplicationController def index if params[:item_id] item = Item.find(params[:item_id]) - @swf_assets = item.swf_assets + @swf_assets = item.swf_assets.includes_depth if params[:body_id] @swf_assets = @swf_assets.fitting_body_id(params[:body_id]) else @@ -16,29 +16,31 @@ class SwfAssetsController < ApplicationController elsif params[:pet_type_id] && params[:item_ids] pet_type = PetType.find(params[:pet_type_id], :select => [:body_id, :species_id]) - @swf_assets = SwfAsset.object_assets. + @swf_assets = SwfAsset.object_assets.includes_depth. fitting_body_id(pet_type.body_id). for_item_ids(params[:item_ids]). with_parent_ids json = @swf_assets.map { |a| a.as_json(:parent_id => a.parent_id.to_i, :for => 'wardrobe') } elsif params[:pet_state_id] - @swf_assets = PetState.find(params[:pet_state_id]).swf_assets.all + @swf_assets = PetState.find(params[:pet_state_id]).swf_assets. + includes_depth.all pet_state_id = params[:pet_state_id].to_i json = @swf_assets.map { |a| a.as_json(:parent_id => pet_state_id, :for => 'wardrobe') } elsif params[:pet_type_id] - @swf_assets = PetType.find(params[:pet_type_id]).pet_states.emotion_order.first.swf_assets + @swf_assets = PetType.find(params[:pet_type_id]).pet_states.emotion_order + .first.swf_assets.includes_depth elsif params[:ids] @swf_assets = [] if params[:ids][:biology] - @swf_assets += SwfAsset.biology_assets.where(:remote_id => params[:ids][:biology]).all + @swf_assets += SwfAsset.includes_depth.biology_assets.where(:remote_id => params[:ids][:biology]).all end if params[:ids][:object] - @swf_assets += SwfAsset.object_assets.where(:remote_id => params[:ids][:object]).all + @swf_assets += SwfAsset.includes_depth.object_assets.where(:remote_id => params[:ids][:object]).all end elsif params[:body_id] && params[:item_ids] # DEPRECATED in favor of pet_type_id and item_ids swf_assets = SwfAsset.arel_table - @swf_assets = SwfAsset.object_assets. + @swf_assets = SwfAsset.includes_depth.object_assets. select('swf_assets.*, parents_swf_assets.parent_id'). fitting_body_id(params[:body_id]). for_item_ids(params[:item_ids]) diff --git a/app/helpers/items_helper.rb b/app/helpers/items_helper.rb index 72afaf2e..e7343564 100644 --- a/app/helpers/items_helper.rb +++ b/app/helpers/items_helper.rb @@ -73,7 +73,7 @@ module ItemsHelper end def list_zones(zones, method=:label) - zones.sort { |x,y| x.label <=> y.label }.map(&method).join(', ') + zones.map(&method).join(', ') end def nc_icon @@ -125,7 +125,8 @@ module ItemsHelper def build_on_pet_types(species, special_color=nil, &block) species_ids = species.map(&:id) pet_types = special_color ? - PetType.where(:color_id => special_color.id, :species_id => species_ids).order(:species_id) : + PetType.where(:color_id => special_color.id, :species_id => species_ids). + order(:species_id).includes_child_translations : PetType.random_basic_per_species(species.map(&:id)) pet_types.map(&block).join.html_safe end diff --git a/app/models/item.rb b/app/models/item.rb index 762d5211..404b1028 100644 --- a/app/models/item.rb +++ b/app/models/item.rb @@ -110,25 +110,27 @@ class Item < ActiveRecord::Base @wanted end - def restricted_zones - unless @restricted_zones - @restricted_zones = [] - zones_restrict.split(//).each_with_index do |switch, id| - @restricted_zones << Zone.find(id.to_i + 1) if switch == '1' - end - end - @restricted_zones + def restricted_zones(options={}) + options[:scope] ||= Zone.scoped + options[:scope].find(restricted_zone_ids) end def restricted_zone_ids - restricted_zones.map(&:id) + unless @restricted_zone_ids + @restricted_zone_ids = [] + zones_restrict.split(//).each_with_index do |switch, id| + @restricted_zone_ids << (id.to_i + 1) if switch == '1' + end + end + @restricted_zone_ids end def occupied_zone_ids occupied_zones.map(&:id) end - def occupied_zones + def occupied_zones(options={}) + options[:scope] ||= Zone.scoped all_body_ids = [] zone_body_ids = {} selected_assets = swf_assets.select('body_id, zone_id').each do |swf_asset| @@ -137,12 +139,11 @@ class Item < ActiveRecord::Base body_ids << swf_asset.body_id unless body_ids.include?(swf_asset.body_id) all_body_ids << swf_asset.body_id unless all_body_ids.include?(swf_asset.body_id) end - zones = [] + zones = options[:scope].find(zone_body_ids.keys) + zones_by_id = zones.inject({}) { |h, z| h[z.id] = z; h } total_body_ids = all_body_ids.size zone_body_ids.each do |zone_id, body_ids| - zone = Zone.find(zone_id) - zone.sometimes = true if body_ids.size < total_body_ids - zones << zone + zones_by_id[zone_id].sometimes = true if body_ids.size < total_body_ids end zones end diff --git a/app/models/item/search/query.rb b/app/models/item/search/query.rb index dca74fdc..88f8bd80 100644 --- a/app/models/item/search/query.rb +++ b/app/models/item/search/query.rb @@ -90,8 +90,8 @@ class Item end species.id }, - :zone => lambda { |name| - zone_set = Zone.find_set(name) + :zone => lambda { |label| + zone_set = Zone.with_plain_label(label) unless zone_set Item::Search.error 'not_found.zone', :zone_name => name end diff --git a/app/models/outfit.rb b/app/models/outfit.rb index c2c2cbba..76ddf1ea 100644 --- a/app/models/outfit.rb +++ b/app/models/outfit.rb @@ -84,7 +84,7 @@ class Outfit < ActiveRecord::Base # ordered from bottom to top. Careful: this method is memoized, so if the # image layers change after its first call we'll get bad results. def image_layers - @image_layers ||= visible_assets_with_images.sort { |a, b| a.zone.depth <=> b.zone.depth } + @image_layers ||= visible_assets_with_images.sort { |a, b| a.depth <=> b.depth } end # Creates and writes the thumbnail images for this outfit iff the new image @@ -177,9 +177,10 @@ class Outfit < ActiveRecord::Base end def visible_assets - biology_assets = pet_state.swf_assets + biology_assets = pet_state.swf_assets.includes(:zone) object_assets = SwfAsset.object_assets. - fitting_body_id(pet_state.pet_type.body_id).for_item_ids(worn_item_ids) + fitting_body_id(pet_state.pet_type.body_id).for_item_ids(worn_item_ids). + includes(:zone) # Now for fun with bitmasks! Rather than building a bunch of integer arrays # here, we instead go low-level and use bit-level operations. Build the diff --git a/app/models/pet_type.rb b/app/models/pet_type.rb index f34aa7ca..66f679f1 100644 --- a/app/models/pet_type.rb +++ b/app/models/pet_type.rb @@ -19,8 +19,12 @@ class PetType < ActiveRecord::Base scope :nonstandard_colors, lambda { where(:color_id => Color.nonstandard) } + scope :includes_child_translations, + lambda { includes({:color => :translations, :species => :translations}) } + def self.standard_pet_types_by_species_id - PetType.where(:color_id => Color.basic).group_by(&:species_id) + PetType.where(:color_id => Color.basic).includes_child_translations. + group_by(&:species_id) end def self.standard_body_ids @@ -33,8 +37,9 @@ class PetType < ActiveRecord::Base def self.random_basic_per_species(species_ids) random_pet_types = [] + standards = self.standard_pet_types_by_species_id species_ids.each do |species_id| - pet_types = standard_pet_types_by_species_id[species_id] + pet_types = standards[species_id] random_pet_types << pet_types[rand(pet_types.size)] if pet_types end random_pet_types diff --git a/app/models/swf_asset.rb b/app/models/swf_asset.rb index f5814a45..8b8e1f9c 100644 --- a/app/models/swf_asset.rb +++ b/app/models/swf_asset.rb @@ -23,6 +23,10 @@ class SwfAsset < ActiveRecord::Base include SwfConverter converts_swfs :size => IMAGE_SIZES[:large], :output_sizes => IMAGE_SIZES.values + + belongs_to :zone + + scope :includes_depth, lambda { includes(:zone) } def local_swf_path LOCAL_ASSET_DIR.join(local_path_within_outfit_swfs) @@ -200,10 +204,6 @@ class SwfAsset < ActiveRecord::Base self.zone.type_id < 3 || (@item && @item.body_specific?) end - def zone - Zone.find(zone_id) - end - def origin_pet_type=(pet_type) self.body_id = pet_type.body_id end diff --git a/app/models/zone.rb b/app/models/zone.rb index fa3bc3d8..52883f5d 100644 --- a/app/models/zone.rb +++ b/app/models/zone.rb @@ -1,49 +1,32 @@ -class Zone < StaticResource - ATTRIBUTE_NAMES = ['id', 'label', 'depth', 'type_id'] - ZONE_SETS = {} +class Zone < ActiveRecord::Base + translates :label, :plain_label - attr_reader *ATTRIBUTE_NAMES # When selecting zones that an asset occupies, we allow the zone to set # whether or not the zone is "sometimes" occupied. This is false by default. attr_writer :sometimes - - def initialize(attributes) - ATTRIBUTE_NAMES.each do |name| - instance_variable_set "@#{name}", attributes[name] - end - end + + scope :alphabetical, lambda { + includes_translations.order(Zone::Translation.arel_table[:label]) + } + scope :includes_translations, lambda { includes(:translations) } + scope :with_plain_label, lambda { |label| + t = Zone::Translation.arel_table + includes(:translations).where(t[:plain_label].eq(Zone.plainify_label(label))) + } def uncertain_label @sometimes ? "#{label} sometimes" : label end - def self.find_set(name) - ZONE_SETS[plain(name)] + def self.all_plain_labels + Zone.select([:id]).includes(:translations).all.map(&:plain_label).uniq.sort end - def self.plain(name) - name.delete('\- /').downcase - end - - n = 0 - @objects = YAML.load_file(Rails.root.join('config', 'zones.yml')).map do |a| - a['id'] = (n += 1) - obj = new(a) - plain_name = plain(obj.label) - - ZONE_SETS[plain_name] ||= [] - ZONE_SETS[plain_name] << obj - obj - end - n = nil - - # Add aliases to keys like "lowerforegrounditem" to "lowerforeground" - # ...unless there's already such a key, like "backgrounditem" to "background", - # in which case we don't, because that'd be silly. - ZONE_SETS.keys.each do |name| - if name.end_with?('item') - stripped_name = name[0..-5] - ZONE_SETS[stripped_name] ||= ZONE_SETS[name] + def self.plainify_label(label) + plain_label = label.delete('\- /').downcase + if plain_label.end_with?('item') + plain_label = plain_label[0..-5] end + plain_label end end diff --git a/app/views/items/show.html.haml b/app/views/items/show.html.haml index 02344e95..51610a89 100644 --- a/app/views/items/show.html.haml +++ b/app/views/items/show.html.haml @@ -53,13 +53,13 @@ #item-zones %p %strong #{t '.zones.occupied_header'}: - = list_zones @item.occupied_zones, :uncertain_label + = list_zones @occupied_zones, :uncertain_label %p %strong #{t '.zones.restricted_header'}: - - if @item.restricted_zones.empty? + - if @restricted_zones.empty? = t '.zones.none' - else - = list_zones @item.restricted_zones + = list_zones @restricted_zones #trade-hangers - [true, false].each do |owned| diff --git a/db/migrate/20130121221226_create_zones.rb b/db/migrate/20130121221226_create_zones.rb new file mode 100644 index 00000000..4d7a7a79 --- /dev/null +++ b/db/migrate/20130121221226_create_zones.rb @@ -0,0 +1,14 @@ +class CreateZones < ActiveRecord::Migration + def self.up + create_table :zones do |t| + t.integer :depth + t.integer :type_id + end + Zone.create_translation_table! :label => :string, :plain_label => :string + end + + def self.down + drop_table :zones + Zone.drop_translation_table! + end +end diff --git a/db/schema.rb b/db/schema.rb index 6e1d4d80..6fe68f87 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130121205607) do +ActiveRecord::Schema.define(:version => 20130121221226) do create_table "auth_servers", :force => true do |t| t.string "short_name", :limit => 10, :null => false @@ -286,11 +286,21 @@ ActiveRecord::Schema.define(:version => 20130121205607) do t.integer "wanted_closet_hangers_visibility", :default => 1, :null => false end + create_table "zone_translations", :force => true do |t| + t.integer "zone_id" + t.string "locale" + t.string "label" + t.string "plain_label" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "zone_translations", ["locale"], :name => "index_zone_translations_on_locale" + add_index "zone_translations", ["zone_id"], :name => "index_zone_translations_on_zone_id" + create_table "zones", :force => true do |t| - t.integer "depth", :limit => 1, :null => false - t.integer "type_id", :limit => 1, :null => false - t.string "type", :limit => 40, :null => false - t.string "label", :limit => 40, :null => false + t.integer "depth" + t.integer "type_id" end end diff --git a/db/seeds.rb b/db/seeds.rb index 87cadcf3..c49ebbac 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -153,3 +153,56 @@ Color.create(:id => 97, :name => "elderlyboy", :basic => false, :standard => tru Color.create(:id => 98, :name => "elderlygirl", :basic => false, :standard => true) Color.create(:id => 99, :name => "stealthy", :basic => false, :standard => true) Color.create(:id => 100, :name => "dimensional", :basic => false, :standard => true) + +Zone.create(:id => 1, :label => "Music", :plain_label => "music", :depth => 1, :type_id => 4) +Zone.create(:id => 2, :label => "Sound Effects", :plain_label => "soundeffects", :depth => 2, :type_id => 4) +Zone.create(:id => 3, :label => "Background", :plain_label => "background", :depth => 3, :type_id => 3) +Zone.create(:id => 4, :label => "Biology Effects", :plain_label => "biologyeffects", :depth => 6, :type_id => 1) +Zone.create(:id => 5, :label => "Hind Biology", :plain_label => "hindbiology", :depth => 7, :type_id => 1) +Zone.create(:id => 6, :label => "Markings", :plain_label => "markings", :depth => 8, :type_id => 2) +Zone.create(:id => 7, :label => "Hind Disease", :plain_label => "hinddisease", :depth => 9, :type_id => 1) +Zone.create(:id => 8, :label => "Hind Cover", :plain_label => "hindcover", :depth => 10, :type_id => 2) +Zone.create(:id => 9, :label => "Hind Transient Biology", :plain_label => "hindtransientbiology", :depth => 11, :type_id => 1) +Zone.create(:id => 10, :label => "Hind Drippings", :plain_label => "hinddrippings", :depth => 12, :type_id => 1) +Zone.create(:id => 11, :label => "Backpack", :plain_label => "backpack", :depth => 13, :type_id => 2) +Zone.create(:id => 12, :label => "Wings Transient Biology", :plain_label => "wingstransientbiology", :depth => 14, :type_id => 1) +Zone.create(:id => 13, :label => "Wings", :plain_label => "wings", :depth => 15, :type_id => 2) +Zone.create(:id => 14, :label => "Hair Back", :plain_label => "hairback", :depth => 17, :type_id => 1) +Zone.create(:id => 15, :label => "Body", :plain_label => "body", :depth => 18, :type_id => 1) +Zone.create(:id => 16, :label => "Markings", :plain_label => "markings", :depth => 19, :type_id => 2) +Zone.create(:id => 17, :label => "Body Disease", :plain_label => "bodydisease", :depth => 20, :type_id => 1) +Zone.create(:id => 18, :label => "Feet Transient Biology", :plain_label => "feettransientbiology", :depth => 21, :type_id => 1) +Zone.create(:id => 19, :label => "Shoes", :plain_label => "shoes", :depth => 22, :type_id => 2) +Zone.create(:id => 20, :label => "Lower-body Transient Biology", :plain_label => "lowerbodytransientbiology", :depth => 23, :type_id => 1) +Zone.create(:id => 21, :label => "Trousers", :plain_label => "trousers", :depth => 24, :type_id => 2) +Zone.create(:id => 22, :label => "Upper-body Transient Biology", :plain_label => "upperbodytransientbiology", :depth => 25, :type_id => 1) +Zone.create(:id => 23, :label => "Shirt/Dress", :plain_label => "shirtdress", :depth => 26, :type_id => 2) +Zone.create(:id => 24, :label => "Necklace", :plain_label => "necklace", :depth => 28, :type_id => 2) +Zone.create(:id => 25, :label => "Gloves", :plain_label => "gloves", :depth => 29, :type_id => 2) +Zone.create(:id => 26, :label => "Jacket", :plain_label => "jacket", :depth => 30, :type_id => 2) +Zone.create(:id => 27, :label => "Collar", :plain_label => "collar", :depth => 31, :type_id => 2) +Zone.create(:id => 28, :label => "Body Drippings", :plain_label => "bodydrippings", :depth => 32, :type_id => 1) +Zone.create(:id => 29, :label => "Ruff", :plain_label => "ruff", :depth => 33, :type_id => 1) +Zone.create(:id => 30, :label => "Head", :plain_label => "head", :depth => 34, :type_id => 1) +Zone.create(:id => 31, :label => "Markings", :plain_label => "markings", :depth => 35, :type_id => 2) +Zone.create(:id => 32, :label => "Head Disease", :plain_label => "headdisease", :depth => 36, :type_id => 1) +Zone.create(:id => 33, :label => "Eyes", :plain_label => "eyes", :depth => 37, :type_id => 1) +Zone.create(:id => 34, :label => "Mouth", :plain_label => "mouth", :depth => 38, :type_id => 1) +Zone.create(:id => 35, :label => "Glasses", :plain_label => "glasses", :depth => 41, :type_id => 2) +Zone.create(:id => 36, :label => "Earrings", :plain_label => "earrings", :depth => 39, :type_id => 2) +Zone.create(:id => 37, :label => "Hair Front", :plain_label => "hairfront", :depth => 40, :type_id => 1) +Zone.create(:id => 38, :label => "Head Transient Biology", :plain_label => "headtransientbiology", :depth => 42, :type_id => 1) +Zone.create(:id => 39, :label => "Head Drippings", :plain_label => "headdrippings", :depth => 43, :type_id => 1) +Zone.create(:id => 40, :label => "Hat", :plain_label => "hat", :depth => 44, :type_id => 2) +Zone.create(:id => 41, :label => "Earrings", :plain_label => "earrings", :depth => 45, :type_id => 2) +Zone.create(:id => 42, :label => "Right-hand Item", :plain_label => "righthand", :depth => 46, :type_id => 2) +Zone.create(:id => 43, :label => "Left-hand Item", :plain_label => "lefthand", :depth => 47, :type_id => 2) +Zone.create(:id => 44, :label => "Higher Foreground Item", :plain_label => "higherforeground", :depth => 49, :type_id => 3) +Zone.create(:id => 45, :label => "Lower Foreground Item", :plain_label => "lowerforeground", :depth => 50, :type_id => 3) +Zone.create(:id => 46, :label => "Static", :plain_label => "static", :depth => 48, :type_id => 3) +Zone.create(:id => 47, :label => "Thought Bubble", :plain_label => "thoughtbubble", :depth => 51, :type_id => 3) +Zone.create(:id => 48, :label => "Background Item", :plain_label => "background", :depth => 4, :type_id => 3) +Zone.create(:id => 49, :label => "Right-hand Item", :plain_label => "righthand", :depth => 5, :type_id => 2) +Zone.create(:id => 50, :label => "Hat", :plain_label => "hat", :depth => 16, :type_id => 2) +Zone.create(:id => 51, :label => "Belt", :plain_label => "belt", :depth => 27, :type_id => 2) +Zone.create(:id => 52, :label => "Foreground", :plain_label => "foreground", :depth => 52, :type_id => 3)