Commit graph

226 commits

Author SHA1 Message Date
0261d02137 Downgrade most item validations to be *not nil*, rather than present
Been running into the item "Hanging Plushie Grundo Background Item" not
being modelable, because TNT seem to have left its description blank!

Let's be less picky about what data we take in, but keep the intention
of these validations: to ensure that *we* don't make a mistake and
forget a field when importing items!
2024-11-19 17:00:47 -08:00
ed5b62e161 Use PetType's created_at to predict who an item might be compatible with
This is a basic attempt at the Vandagyre logic, but also things like
"Maraquan items released before the Maraquan X was released"!

I also added a new task, `rails items:update_cached_fields`, which needs
to be run after this change, because it affects the value of
`Item#predicted_fully_modeled?`.

Eyeballing the updated search results for `-is:modeled`, this feels
pretty close? I'm guessing it's not perfect (e.g. maybe a pet type we
got modeled late into its existence, or some items that just never did
fit a certain pet), but feels pretty good.

I also know we had the "modeling hints" override in Impress 2020, which
we aren't reading yet. We should probably take that into account here
too!
2024-11-19 16:41:50 -08:00
f6f618c9d5 Add Item.is{_not}_modeled scopes, for use in search later
We're now caching `predicted_fully_modeled?` on the database record, so
we can query by it in the database!

I'm moving on from the model I did in Impress 2020, of writing really
big fancy single-source-of-truth queries based on the assets themselves.

I see the merit of that in terms of theoretical reliability, but in
practice I think it will be *more* reliable to have one *in-code*
definition of modeling status (which we need anyway for generating the
homepage modeling requests), and just save that in a queryable way.
2024-11-19 15:52:52 -08:00
39bed6b157 Make Item's update_cached_fields callback more reliable
In our tests, I discovered an unexpected behavior where calling
`item.swf_assets << swf_asset` wasn't updating computed fields
correctly.

This isn't something we actually do in-app, I think the modeling system
happened to trigger the callbacks in a way that still worked fine?

But I think this is a good idea for reliability, since caching is such
a notoriously difficult thing to get right anyway! And it makes our
tests simpler and clearer.

Specifically, `compatible_body_ids` references `swf_assets`, which, I'm
kinda surprised, *doesn't* include the newly-added asset yet when the
`ParentSwfAssetRelationship.after_save` hook runs while calling
`item.swf_assets << swf_asset`. Reloading it fixes this!
2024-11-19 14:26:06 -08:00
f7109e398a Better handle modeling predictions for items with *no* data
This doesn't generally happen, but did the other day when I rolled back
some of the database's SWF asset records but kept the items—and it was
a bit confusing that the homepage marked them as fully modeled!
2024-11-19 12:15:21 -08:00
e3d196fe87 Revert modeling refactors to the old modeling that worked!
Because we ended up with such a big error, and it doesn't have an easy
fix, I'm wrapping up today by reverting the entire set of refactors
we've done lately, so modeling in production can continue while we
improve this code further over time.

I generated this commit by hand-picking the refactor-y commits
recently, running `git revert --no-commit <hash>` in reverse order,
then manually updating `pet_spec.rb` to reflect the state of the code:
passing the most important behavioral tests, but no longer passing one
of the kinds of annoyances I *did* fix in the new code.

```shell
git revert --no-commit 48c1a58df9
git revert --no-commit 42e7eabdd8
git revert --no-commit d82c7f817a
git revert --no-commit 5264947608
git revert --no-commit 90407403ba
git revert --no-commit 242b85470d
git revert --no-commit 9eaee4a2d4
git revert --no-commit 52ca41dbff
git revert --no-commit c03e7446e3
git revert --no-commit f81415d327
git revert --no-commit 13ceec8fcc
```
2024-11-06 14:31:16 -08:00
42e7eabdd8 Fix modeling bug where compatible_body_ids field was not updating
Ah right, the callbacks in `ParentSwfAssetRelationship` don't get
called when Rails does automatic join-model management stuff. We need
the `Item` to call its `update_cached_fields` callback itself, too!

When fixing this, I found a new bug that arose, in how we infer
`body_id` for assets that fit all pets. Fixing that next!
2024-11-06 13:39:32 -08:00
9eaee4a2d4 Refactor item modeling
Simpler, more encapsulated, and fixes the pending jank stuff in the
tests!
2024-11-03 12:05:37 -08:00
540ce08caa Handle invalid Item state a bit better
Catch missing fields in validation before sending it to the DB, and
skip the Dyeworks stuff if the name is missing.

I ran into this looking into `test/trade_activity_test.rb`, which fails
right now because we try to create a boring placeholder item with
minimal fields, which Dyeworks can't call `name.match()` on!

Now, the test fails with a more helpful error about the item being
invalid. Next, I'll fix that!
2024-10-21 14:24:45 -07:00
71f0aa4908 Oops, fix modeling logic
Oh huh, I guess most of the new items we had when I rewrote this were
Maraquan, and I didn't test enough on standard species-specific items.

Before this change, partially-modeled items for standard pets would
appear as fully modeled, because the presence of the "nonstandard"
color Orange (because of the Orange Chia) meant that the "standard" key
didn't actually have any unique bodies (it was all `["standard", 47]`).

Here, I take my own comments' advice and move away from the standard
label as part of the logic. Instead, we look first for nonstandard
colors with unique bodies, which we'll call out as modelable; and then
check whether there are any basic bodies *not* covered by those special
colors.

That way, compatibility with the Maraquan Acara (a unique body) means
we'll treat Maraquan as a modelable color; and then we'll ignore the
basic bodies, even though it *does* fit the basic Mynci, because there
aren't any compatible basic bodies that aren't *also* Maraquan bodies.

This also means that compatibility with both the Blue Acara and Orange
Acara does *not* preclude a normal item from needing basic pets for
models: because, while Orange is a slightly nonstandard color in the
case of Chia, it doesn't have its own unique body for this item, so we
ignore it when predicting compatibility with basic colors.
2024-10-08 22:46:11 -07:00
bd001e643e Oops, avoid scooping up weird Chia bodies in predicted_body_ids
Before this change, a fully-modeled item (Dyeworks Burgundy: Gown of
the Night) was displaying as still needing the Chia. This was because
looking for "standard" body IDs like this caught up some of the weird
Chia bodies.

I think there's probably something here where we need to like, relabel
certain colors? But honestly, the better version of this logic would
probably be to lean more into the `basic` label in this logic.

But hey, that's a refactor for another time. I gotta go eat!
2024-10-03 15:39:35 -07:00
fe4db1b605 Improve prediction for what pets need modeling for an item
Noticing a lot of Maraquan items on the homepage today, and they're
doing that thing of expecting standard body types to be relevant too,
because I think we wrote this logic before the Maraquan Mynci ended up
having the same standard Mynci body? (Maybe? Or maybe I'm being
ahistorical and I just wrote this wrong to begin with lol)

In any case, this is more accurate, and I think I'm also maybe
incidentally noticing that it's running faster, at least in my brief
before/after production testing? (There's *more* queries, like 100! But
many of them are *very* fast lookups, coming in at under 1ms—and also a
lot of them are dupes being served by Rails's request-scoped query
cache.)
2024-10-03 13:49:15 -07:00
03e4233f67 Use cached compatible body IDs on homepage modeling code
This should make it load way faster! Maybe don't even need to mess with
caching the resulting HTML anymore, like we currently do?
2024-10-02 17:55:20 -07:00
b6bddb14be Oops, fix new bug in homepage modeling code
Missed a spot on `Item#basic_body_ids`!
2024-10-02 17:54:14 -07:00
e52838ba70 Use Rails serialize method to save/load cached fields in Item
Just packing some serialization complexity away into its own thing, so
the model code doesn't need to sweat it!
2024-10-02 17:50:42 -07:00
7ba68c52d4 Simplify homepage modeling code a bit
I have some other changes planned too, but these are some easy ones. I
also turn back on this stuff in development, in hopes that my changes
can make these queries fast enough to not be a big deal anymore!
2024-10-02 17:26:32 -07:00
26add4577c Use cached fields for item searches, instead of big joins
This is the second part of the previous change `efda6d74`, in which we
switch out the item search query conditions!

This was a two-parter to ease deployment: first deploy the change with
the migration, then *run* the migration (because it's an unusually slow
one), then deploy this change that actually uses it.

Another way to approach this would've been to deploy it all in one
commit, but not set it as `current` until we had run the migration.
That would have been a reasonable approach too!
2024-09-30 23:16:03 -07:00
efda6d74ab Add cached fields to Item model for searching, but don't use them yet
This is the first part of a change to improve search performance, by
caching occupied zone IDs and supported body IDs onto the Item record
itself, instead of always doing joins with `SwfAsset`.

It's unfortunate, because part of the power of SQL is joins! But doing
joins with big tables, in ways that can't take advantage of indexes in
the same ways as we often want to, is… slow.

It's possible there's something I'm misunderstanding about SQL
optimization, and this _could_ be done with query optimization or
indexes instead of duplicating data like this? This complexity carries
the risk of data getting out of sync in unforeseen ways. But this is
what I know how to do, and it seems to be working, so! Okay!
2024-09-30 23:10:44 -07:00
989c96fd2b Oops, fix pb_item for "Royal Girl Elephante Gold Bracelets" and similar
There's some funny bugs we had here, like "Relic Elephante Jewellery"
and "Royal Girl Skeith Bodice" getting assigned "Ice", and
"Tyrannian Meerca Spear" being "Pea" lmao

I went and checked all the assignments now and they look good to me!

```ruby
Item.is_pb.order(:name).
  map { |i| [i.pb_color&.human_name, i.name] }
```
2024-09-13 19:56:41 -07:00
6f08abc3aa Add html5 badge to new item previews 2024-09-05 18:48:41 -07:00
edcb21558a Drastically reduce queries for item page preview
Oh right okay, I made a sloppy perf hack long ago, and now let's
actually clean it up!
2024-09-05 17:52:35 -07:00
176ab20fd1 Cache the Item#appearances field
We call it enough times on this page, and it *does* have a SQL query,
that I want to cache it! (Also I want to make it fewer species queries
if I can tbh…)
2024-09-05 17:41:04 -07:00
9f44fd47e4 Add "No data yet" to species face tooltip when needed, in item previews 2024-09-03 17:27:43 -07:00
2b2bffd9da Disable pet faces that the item doesn't fit, in new item previews 2024-09-03 16:42:04 -07:00
36f8efadbf Add more detailed zone occupy info to simplified item preview page
Adapting what the Impress 2020 UI does, but in Ruby instead!

I feel like this is case is really starting to show the power of doing
this stuff in Rails instead of via an API… we can *really* take
advantage of our models and our handy idioms at all points. This is
just so much less *code* than this feature takes in Node + GraphQL +
React.
2024-09-03 12:55:10 -07:00
e0f9a27adc Merge branch 'main' into simpler-item-previews 2024-08-31 13:43:10 -07:00
1c36276865 Remove unused special_color logic from Item
We used to use this to determine what color to show by default on the
item page preview for, like, Maraquan-specific items. Now, we infer it
from our actual customization data, rather than these heuristics!

There's still a database field for `Item#manual_special_color_id`. We
can still read and write this from the support UI, and Impress 2020
still slightly uses it from the homepage, so I'm not removing from the
database right now.
2024-08-31 13:42:25 -07:00
8ab5af1aca Remove unused logic for whether a zone is "sometimes" occupied
I'm about to reimplement the more-robust version of what this used to
be: how the item page used to say "sometimes" after certain zones in
the occupied list.

Now, we're going to do parity with 2020, and list the actual species!

I like that this takes away the weird `#sometimes` method on the `Zone`
class, which was always an odd hack for just this small thing.
2024-08-31 13:16:47 -07:00
bd62476722 Add basic zone info to simpler item previews
We're missing the feature where we enumerate the exact species in
ambiguous cases, though!
2024-08-31 13:11:50 -07:00
ac002f3151 Track preferred color/species for new item page previews
Also adapted from the Impress 2020 logic!

Note that I refactored `compatible_pet_type` to a series of scopes on
`PetType`. I think this is a simpler, clearer, and more flexible API!
2024-07-01 17:38:31 -07:00
fe6035d438 Default to compatible pet types in new item page preview
Just adapted from Impress 2020 logic again, easy peasy!
2024-07-01 17:20:38 -07:00
3f38fbd1b0 Support zone restriction in new item preview
Adapted from wardrobe-2020's `getVisibleLayers`! Thanks past-Matchu for
all the comments lol!
2024-07-01 16:54:39 -07:00
74748acaaf Refactor more of item outfit preview into the Outfit class
This is a cute thing that I think sets us up for other stuff down the
line: move more of the outfit appearance logic into the `Outfit` class!
Now, we set up the item page with a temporary instance of `Outfit`,
then ask for its `visible_layers`.

Still missing restricted-zones logic and such, that's next!
2024-07-01 16:07:25 -07:00
ea17e76c39 [WIP] Start replacing item page preview with simpler HTML-based version
Just stripping out the big React component, and having Rails output it!

There's a lot of work rn in extracting the Impress 2020 dependency from
the `wardrobe-2020` React app, and I'm just curious to see if we can
simplify it at all by pulling this stuff *way* back to basics, and
deleting the item page part of `wardrobe-2020` altogether.

In this draft, we regress a lot of functionality: it just shows the
item on a Blue Acara, with no ability to change it! I'm gonna play with
putting more of that back in.

I also haven't actually removed any of the item page React code; I just
stopped calling it. That can be a cleanup for another time, once we're
confident in this experiment!
2024-07-01 15:35:58 -07:00
a70b70be7d Merge remote-tracking branch 'origin/main' 2024-07-01 14:56:08 -07:00
5401ea984a Merge remote-tracking branch 'origin/main' 2024-06-22 18:47:10 -07:00
97abd6e438 Add probabilities to Dyeworks items in Item Getting Guide
I'm gonna better explain the gacha nature, I'm doing this part first!
2024-06-20 12:54:39 -07:00
1d250f3148 Remove unused Item.with_closet_hangers scope
Idk why we thought this made sense way back when? But it evidently has
no call sites now so. Goodbye!
2024-06-19 17:49:18 -07:00
015010345a Extract Dyeworks methods into Item::Dyeworks module
There's just starting to be a lot going on, so I pulled them out into
here!

I also considered a like, `Item::DyeworksStatus` class, and then you'd
go like, `item.dyeworks.buyable?`. But idk, I think it's nice that the
current API is simple for callers, and being able to do things like
`items.filter(&:dyeworks_buyable?)` is pretty darn convenient.

This solution lets us keep the increasing number of Dyeworks methods
from polluting the main `item.rb`, while still keeping the API
identical!
2024-06-18 15:21:43 -07:00
26dfe13b0e Parse "Limited Dyeworks" items from Owls
Yay thank you Owls team! I might also try to parse the dates too, the
format seems to be "Owls: Limited Dyeworks - Dyeable Thru July 15"
2024-06-18 14:59:09 -07:00
bbd1849e19 Oops, fix crash for Dyeworks without Owls info in Item Getting Guide
Silly mistake, right, we might not have a trade value listed! This is
relevant for the new Dyeworks items that just came out like a few hours
ago, which Owls doesn't have info for yet.
2024-06-17 13:07:03 -07:00
9f536f81b3 Refactor to use a new Item#source method for where an item is from
I'm doing this in preparation for maybe trying to load some of this
info into the outfit editor, too!
2024-06-16 12:37:53 -07:00
b22ccbc2a3 Use Owls to check for Permanent Dyeworks items
Previously, I added a Dyeworks section that was incorrect: the base
item being available in the NC Mall does *not* mean you can necessarily
dye it with a potion!

In this change, we lean on Owls to tell us more about Dyeworks status,
and only group items in this section that Owls has marked as "Permanent
Dyeworks".

We don't have support for limited-time Dyeworks items yet—I've sent out
a message asking the Owls team for more info on what they do for those
items!
2024-06-09 14:46:24 -07:00
5de9e2a27b Add Dyeworks section to Item Getting Guide (but it's currently wrong!)
I started writing this up, then sent a preview to a friend, and he was
like "oh cool, but also this is not correct?"

I didn't realize Dyeworks has limited-time support to be *able* to dye
certain items. Hey, glad we're writing this guide for people like me,
then! lol

I wonder if we can lean on Owls for this. It seems like they already
list "Permanent Dyeworks" for some items, I wonder if they say
something special for active limited-edition Dyeworks items!
2024-06-09 13:25:59 -07:00
857cb547ed Add Item#dyeworks_base_item database field, and populate it
In this change, instead of *always* inferring the Dyeworks base item
from the item name at runtime, we now have a database field that tracks
it, and auto-populates whenever an item *seems* to need a Dyeworks base
item but doesn't have one yet.

This will enable us to set the base item manually in cases where it
can't be inferred, and load Dyeworks base items for the Item Getting
Guide in one query with `includes(:dyeworks_base_item)`.

This migration does a bit more of the fix-em-up scripting work *in* the
migration itself than I usually do, mainly because there's so much in
this one that I think being extra-explicit is useful. We make sure to
do it gracefully though!
2024-06-07 20:10:06 -07:00
68cb44d159 Add logic to infer the base for Dyeworks items
This works for most of the current 1,094 Dyeworks items! But there are
a few exceptions, for cases where the base item name is not quite the
same (e.g. the Dyeworks version is more concise). Maybe we'll add a
database field to override this?

- Dyeworks Baby Blue: Baby Valentine Jumper
- Dyeworks Baby Pink: Baby Valentine Jumper
- Dyeworks Black: Field of Flowers
- Dyeworks Black: Games Master Challenge 2010 Lulu Shirt
- Dyeworks Blue: Field of Flowers
- Dyeworks Blue: Stars and Glitter Facepaint
- Dyeworks Brown: Hanging Winter Candles Garland
- Dyeworks Green: Stars and Glitter Facepaint
- Dyeworks Magenta: Lovely Berry Blush
- Dyeworks Orange & Pink: Winter Lights Effects
- Dyeworks Orange: Games Master Challenge 2010 Lulu Shirt
- Dyeworks Peach: Lovely Berry Blush
- Dyeworks Purple: Baby Valentine Jumper
- Dyeworks Purple: Games Master Challenge 2010 Lulu Shirt
- Dyeworks Purple: Hanging Winter Candles Garland
- Dyeworks Purple: Stars and Glitter Facepaint
- Dyeworks Red & Green: Winter Lights Effects
- Dyeworks Silver: Hanging Winter Candles Garland
- Dyeworks Soft Pink: Lovely Berry Blush
- Dyeworks Yellow & Magenta: Winter Lights Effects
- Dyeworks Yellow: Field of Flowers
2024-06-07 19:35:43 -07:00
31c281390d Add explanations for why Item#pb_{species,color} would return nil 2024-06-05 19:46:12 -07:00
193b1fa5e3 Improve performance for occupies:X searches
I noticed in the app that these queries were slowwww! I was able to
track it down to a bad query plan, as we explain in the comment.

I searched online for "mysql query performance filter on one join table
sort by another", and was surprised to find this answer suggest a
subquery, which I've often been told to expect to be slower compared to
joins? But it certainly worked in this case!

https://stackoverflow.com/questions/35679693/mysql-optimize-join-with-filter-and-order-on-different-tables
2024-06-03 11:45:51 -07:00
758b62e7d5 Improve performance of Owls values in Item Getting Guide
Now we preload them all concurrently, instead of in sequence when the
template gets around to asking for them!
2024-05-27 16:21:22 -07:00
d34bebc336 Use a pet face when there's no paint brush, in Item Getting Guide
Now, for colors like Mutant or Magma where there's no paint brush
image to show, we use a sample pet image instead, to help it have equal
visual weight and clarity as the cases with the paint brushes.

We do some cleverness in here to make sure to always show the relevant
species, if possible!
2024-05-22 17:53:52 -07:00