Compare commits
6 commits
26add4577c
...
860b8eef72
Author | SHA1 | Date | |
---|---|---|---|
860b8eef72 | |||
61e22e3943 | |||
03e4233f67 | |||
b6bddb14be | |||
e52838ba70 | |||
7ba68c52d4 |
7 changed files with 73 additions and 71 deletions
|
@ -50,10 +50,9 @@ class OutfitsController < ApplicationController
|
||||||
@colors = Color.alphabetical
|
@colors = Color.alphabetical
|
||||||
@species = Species.alphabetical
|
@species = Species.alphabetical
|
||||||
|
|
||||||
# HACK: Skip this in development, because it's slow!
|
|
||||||
unless Rails.env.development?
|
|
||||||
newest_items = Item.newest.
|
newest_items = Item.newest.
|
||||||
select(:id, :name, :updated_at, :thumbnail_url, :rarity_index, :is_manually_nc)
|
select(:id, :name, :updated_at, :thumbnail_url, :rarity_index,
|
||||||
|
:is_manually_nc, :cached_compatible_body_ids)
|
||||||
.limit(18)
|
.limit(18)
|
||||||
@newest_modeled_items, @newest_unmodeled_items =
|
@newest_modeled_items, @newest_unmodeled_items =
|
||||||
newest_items.partition(&:predicted_fully_modeled?)
|
newest_items.partition(&:predicted_fully_modeled?)
|
||||||
|
@ -70,7 +69,6 @@ class OutfitsController < ApplicationController
|
||||||
@newest_unmodeled_items_predicted_missing_species_by_color[item] = h
|
@newest_unmodeled_items_predicted_missing_species_by_color[item] = h
|
||||||
@newest_unmodeled_items_predicted_modeled_ratio[item] = item.predicted_modeled_ratio
|
@newest_unmodeled_items_predicted_modeled_ratio[item] = item.predicted_modeled_ratio
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
@species_count = Species.count
|
@species_count = Species.count
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,9 @@ class Item < ApplicationRecord
|
||||||
|
|
||||||
SwfAssetType = 'object'
|
SwfAssetType = 'object'
|
||||||
|
|
||||||
|
serialize :cached_compatible_body_ids, coder: Serializers::IntegerSet
|
||||||
|
serialize :cached_occupied_zone_ids, coder: Serializers::IntegerSet
|
||||||
|
|
||||||
has_many :closet_hangers
|
has_many :closet_hangers
|
||||||
has_one :contribution, as: :contributed, inverse_of: :contributed
|
has_one :contribution, as: :contributed, inverse_of: :contributed
|
||||||
has_one :nc_mall_record
|
has_one :nc_mall_record
|
||||||
|
@ -258,8 +261,8 @@ class Item < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_cached_fields
|
def update_cached_fields
|
||||||
self.cached_occupied_zone_ids = occupied_zone_ids.sort.join(",")
|
self.cached_occupied_zone_ids = occupied_zone_ids
|
||||||
self.cached_compatible_body_ids = compatible_body_ids.sort.join(",")
|
self.cached_compatible_body_ids = compatible_body_ids(use_cached: false)
|
||||||
self.save!
|
self.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -273,58 +276,35 @@ class Item < ApplicationRecord
|
||||||
write_attribute('species_support_ids', replacement)
|
write_attribute('species_support_ids', replacement)
|
||||||
end
|
end
|
||||||
|
|
||||||
def support_species?(species)
|
|
||||||
species_support_ids.blank? || species_support_ids.include?(species.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def modeled_body_ids
|
|
||||||
@modeled_body_ids ||= swf_assets.select('DISTINCT body_id').map(&:body_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def modeled_color_ids
|
|
||||||
# Might be empty if modeled_body_ids is 0. But it's currently not called
|
|
||||||
# in that scenario, so, whatever.
|
|
||||||
@modeled_color_ids ||= PetType.select('DISTINCT color_id').
|
|
||||||
where(body_id: modeled_body_ids).
|
|
||||||
map(&:color_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def basic_body_ids
|
|
||||||
@basic_body_ids ||= begin
|
|
||||||
basic_color_ids ||= Color.select([:id]).basic.map(&:id)
|
|
||||||
PetType.select('DISTINCT body_id').
|
|
||||||
where(color_id: basic_color_ids).map(&:body_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def predicted_body_ids
|
def predicted_body_ids
|
||||||
@predicted_body_ids ||= if modeled_body_ids.include?(0)
|
@predicted_body_ids ||= if compatible_body_ids.include?(0)
|
||||||
# Oh, look, it's already known to fit everybody! Sweet. We're done. (This
|
# Oh, look, it's already known to fit everybody! Sweet. We're done. (This
|
||||||
# isn't folded into the case below, in case this item somehow got a
|
# isn't folded into the case below, in case this item somehow got a
|
||||||
# body-specific and non-body-specific asset. In all the cases I've seen
|
# body-specific and non-body-specific asset. In all the cases I've seen
|
||||||
# it, that indicates a glitched item, but this method chooses to reflect
|
# it, that indicates a glitched item, but this method chooses to reflect
|
||||||
# behavior elsewhere in the app by saying that we can put this item on
|
# behavior elsewhere in the app by saying that we can put this item on
|
||||||
# anybody. (Heh. Any body.))
|
# anybody. (Heh. Any body.))
|
||||||
modeled_body_ids
|
compatible_body_ids
|
||||||
elsif modeled_body_ids.size == 1
|
elsif compatible_body_ids.size == 1
|
||||||
# This might just be a species-specific item. Let's be conservative in
|
# This might just be a species-specific item. Let's be conservative in
|
||||||
# our prediction, though we'll revise it if we see another body ID.
|
# our prediction, though we'll revise it if we see another body ID.
|
||||||
modeled_body_ids
|
compatible_body_ids
|
||||||
else
|
else
|
||||||
# If an item is worn by more than one body, then it must be wearable by
|
# If an item is worn by more than one body, then it must be wearable by
|
||||||
# all bodies of the same color. (To my knowledge, anyway. I'm not aware
|
# all bodies of the same color. (To my knowledge, anyway. I'm not aware
|
||||||
# of any exceptions.) So, let's find those bodies by first finding those
|
# of any exceptions.) So, let's find those bodies by first finding those
|
||||||
# colors.
|
# colors.
|
||||||
basic_modeled_body_ids, nonbasic_modeled_body_ids = modeled_body_ids.
|
basic_body_ids = PetType.basic_body_ids
|
||||||
partition { |bi| basic_body_ids.include?(bi) }
|
basic_compatible_body_ids, nonbasic_compatible_body_ids =
|
||||||
|
compatible_body_ids.partition { |bi| basic_body_ids.include?(bi) }
|
||||||
|
|
||||||
output = []
|
output = []
|
||||||
if basic_modeled_body_ids.present?
|
if basic_compatible_body_ids.present?
|
||||||
output += basic_body_ids
|
output += basic_body_ids
|
||||||
end
|
end
|
||||||
if nonbasic_modeled_body_ids.present?
|
if nonbasic_compatible_body_ids.present?
|
||||||
nonbasic_modeled_color_ids = PetType.select('DISTINCT color_id').
|
nonbasic_modeled_color_ids = PetType.select('DISTINCT color_id').
|
||||||
where(body_id: nonbasic_modeled_body_ids).
|
where(body_id: nonbasic_compatible_body_ids).
|
||||||
map(&:color_id)
|
map(&:color_id)
|
||||||
output += PetType.select('DISTINCT body_id').
|
output += PetType.select('DISTINCT body_id').
|
||||||
where(color_id: nonbasic_modeled_color_ids).
|
where(color_id: nonbasic_modeled_color_ids).
|
||||||
|
@ -335,7 +315,7 @@ class Item < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def predicted_missing_body_ids
|
def predicted_missing_body_ids
|
||||||
@predicted_missing_body_ids ||= predicted_body_ids - modeled_body_ids
|
@predicted_missing_body_ids ||= predicted_body_ids - compatible_body_ids
|
||||||
end
|
end
|
||||||
|
|
||||||
def predicted_missing_standard_body_ids_by_species_id
|
def predicted_missing_standard_body_ids_by_species_id
|
||||||
|
@ -355,9 +335,8 @@ class Item < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def predicted_missing_nonstandard_body_pet_types
|
def predicted_missing_nonstandard_body_pet_types
|
||||||
PetType.joins(:color).
|
body_ids = predicted_missing_body_ids - PetType.basic_body_ids
|
||||||
where(body_id: predicted_missing_body_ids - basic_body_ids,
|
PetType.joins(:color).where(body_id: body_ids, colors: {standard: false})
|
||||||
colors: {standard: false})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def predicted_missing_nonstandard_body_ids_by_species_by_color
|
def predicted_missing_nonstandard_body_ids_by_species_by_color
|
||||||
|
@ -387,7 +366,7 @@ class Item < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def predicted_modeled_ratio
|
def predicted_modeled_ratio
|
||||||
modeled_body_ids.size.to_f / predicted_body_ids.size
|
compatible_body_ids.size.to_f / predicted_body_ids.size
|
||||||
end
|
end
|
||||||
|
|
||||||
def as_json(options={})
|
def as_json(options={})
|
||||||
|
@ -397,7 +376,9 @@ class Item < ApplicationRecord
|
||||||
}.merge(options))
|
}.merge(options))
|
||||||
end
|
end
|
||||||
|
|
||||||
def compatible_body_ids
|
def compatible_body_ids(use_cached: true)
|
||||||
|
return cached_compatible_body_ids if use_cached
|
||||||
|
|
||||||
swf_assets.map(&:body_id).uniq
|
swf_assets.map(&:body_id).uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,10 @@ class PetType < ApplicationRecord
|
||||||
"#{color.human_name}-#{species.human_name}"
|
"#{color.human_name}-#{species.human_name}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.basic_body_ids
|
||||||
|
PetType.basic.distinct.pluck(:body_id)
|
||||||
|
end
|
||||||
|
|
||||||
def self.all_by_ids_or_children(ids, pet_states)
|
def self.all_by_ids_or_children(ids, pet_states)
|
||||||
pet_states_by_pet_type_id = {}
|
pet_states_by_pet_type_id = {}
|
||||||
pet_states.each do |pet_state|
|
pet_states.each do |pet_state|
|
||||||
|
|
|
@ -90,7 +90,6 @@
|
||||||
%h3= t '.newest_items.unmodeled.header'
|
%h3= t '.newest_items.unmodeled.header'
|
||||||
%ul#newest-unmodeled-items
|
%ul#newest-unmodeled-items
|
||||||
- @newest_unmodeled_items.each do |item|
|
- @newest_unmodeled_items.each do |item|
|
||||||
- cache "items/#{item.id} modeling_progress locale=#{I18n.locale} updated_at=#{item.updated_at.to_i}" do
|
|
||||||
%li{'data-item-id' => item.id}
|
%li{'data-item-id' => item.id}
|
||||||
= link_to image_tag(item.thumbnail_url), item, :class => 'image-link'
|
= link_to image_tag(item.thumbnail_url), item, :class => 'image-link'
|
||||||
= link_to item, :class => 'header' do
|
= link_to item, :class => 'header' do
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
class AllowNullInItemsCachedFields < ActiveRecord::Migration[7.2]
|
||||||
|
def change
|
||||||
|
# This is a bit more compatible with ActiveRecord's `serialize` utility,
|
||||||
|
# which seems pretty insistent that empty arrays should be saved as `NULL`,
|
||||||
|
# rather than the empty string our serializer would return if called :(
|
||||||
|
change_column_null :items, :cached_compatible_body_ids, true
|
||||||
|
change_column_null :items, :cached_occupied_zone_ids, true
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[7.2].define(version: 2024_10_01_052510) do
|
ActiveRecord::Schema[7.2].define(version: 2024_10_03_004726) do
|
||||||
create_table "alt_styles", charset: "utf8mb4", collation: "utf8mb4_unicode_520_ci", force: :cascade do |t|
|
create_table "alt_styles", charset: "utf8mb4", collation: "utf8mb4_unicode_520_ci", force: :cascade do |t|
|
||||||
t.integer "species_id", null: false
|
t.integer "species_id", null: false
|
||||||
t.integer "color_id", null: false
|
t.integer "color_id", null: false
|
||||||
|
@ -137,8 +137,8 @@ ActiveRecord::Schema[7.2].define(version: 2024_10_01_052510) do
|
||||||
t.text "description", size: :medium, null: false
|
t.text "description", size: :medium, null: false
|
||||||
t.string "rarity", default: "", null: false
|
t.string "rarity", default: "", null: false
|
||||||
t.integer "dyeworks_base_item_id"
|
t.integer "dyeworks_base_item_id"
|
||||||
t.string "cached_occupied_zone_ids", default: "", null: false
|
t.string "cached_occupied_zone_ids", default: ""
|
||||||
t.text "cached_compatible_body_ids", default: "", null: false
|
t.text "cached_compatible_body_ids", default: ""
|
||||||
t.index ["dyeworks_base_item_id"], name: "index_items_on_dyeworks_base_item_id"
|
t.index ["dyeworks_base_item_id"], name: "index_items_on_dyeworks_base_item_id"
|
||||||
t.index ["modeling_status_hint", "created_at", "id"], name: "items_modeling_status_hint_and_created_at_and_id"
|
t.index ["modeling_status_hint", "created_at", "id"], name: "items_modeling_status_hint_and_created_at_and_id"
|
||||||
t.index ["modeling_status_hint", "created_at"], name: "items_modeling_status_hint_and_created_at"
|
t.index ["modeling_status_hint", "created_at"], name: "items_modeling_status_hint_and_created_at"
|
||||||
|
|
11
lib/serializers/integer_set.rb
Normal file
11
lib/serializers/integer_set.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
module Serializers
|
||||||
|
module IntegerSet
|
||||||
|
def self.dump(array)
|
||||||
|
array.sort.join(",")
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.load(string)
|
||||||
|
(string || "").split(",").map(&:to_i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue