filter_spirit icon indicating copy to clipboard operation
filter_spirit copied to clipboard

support for filter variants

Open Xeverous opened this issue 6 years ago • 8 comments

We need a feature which will allow to generate filters with multiple variants/strictness levels from 1 template.


Current idea: decorate blocks (something akin to Python's decorators) and then specify which blocks should be present in each variant.

@chome_items
SocketGroup "RGB" {
        @chrome_items.small {
                Width 2
                Height <= 2 {
                        SetBorderColor color_chromatic_small
                        Show
                }

                Width 1
                Height <= 4 {
                        SetBorderColor color_chromatic_small
                        Show
                }

                SetBorderColor color_chromatic_big
                Show
        }
}

Edit: cleaner goals - a list of what is must-have:

  1. The feature must support all 3 states (generate with Show, generate with Hide, do not generate). In a lot of cases you want the 3rd one - the difference is that items not explicitly hidden may be caught by later blocks - this means that syntax like @Strict(Show) @UberStrict(Hide) is not enough, because (example):
    • You want to hide armourer scraps and whetstones, simply because you don't pick up them and they have no other use.
    • You don't want to hide hammers when you resign from hammer recipe. You want to just not generate a block for them so they can still be catched by chromatic or chaos recipe blocks.
  2. A lot of variants will use exactly the same block, with the only differences being disabling sound effect and changing Show to Hide. The feature should allow to avoid code duplication.
  3. The feature should not require additional files. 1 filter template file => multiple filter variants. We can already generate multiple filters by choosing different league for item price data.
  4. There should a way to specify the file name, since we can not put multiple filters in the same output file. Need ideas for the syntax.
  5. The feature should be independent from theming, which is just a selection of colors/sounds etc. When having X different variants and Y different themes, you should be able to generate all X * Y different filters.
  6. The feature should not impose requirement that each subsequent variant is a subset of another. It should be possible to have different variants, where each one has an independent set of blocks.
  7. Any syntax should be declarative, not imperative.

Xeverous avatar Oct 04 '19 10:10 Xeverous

Just to add a note on how strictness filtering is done in other filters:

Usually you have a base version of said filter which acts as "league start" filter into early maps, this will most likely show way to much loot, but that is need in a league start situation as bad items can still be worth something and you need some gear for your char. It also likely contains a detailed leveling section which is only need for your first character in the league(later characters will have mostly twinked leveling gear, which means you don't really pick up any gear on your way to maps.)

Now when you get into mid tier maps your most likely gonna switch to some stricter filters; the way this is done the easiest is: (I will use StupidFatHobbits filters as an example, as i base my filter on his)

This is an example from the "normal" filter

Show
	BaseType "Vaal Axe" "Coronal Maul" "Exquisite Blade"
	Rarity = Rare
	SetFontSize 34
	SetBorderColor 128 0 0

This is from the Strict version:

Hide
	BaseType "Vaal Axe" "Coronal Maul" "Exquisite Blade"
	Rarity = Rare
	SetFontSize 34
	SetBorderColor 128 0 0

So what you really want is an easy way to toggle the Show/Hide when compiling the filter, this could for example be done by having a tag in front of Show in filter_spirit. Something like this maybe?

BaseType ["Vaal Axe", "Coronal Maul", "Exquisite Blade"]{
    SetBackgroundColor color_rare_t3
    SetFontSize font_t5
    SetBorderColor color_rare_border_t3
    @Strict(Hide) Show
}

When you then complie in filter_spirit you could do something like this:

filter_spirit_cli.exe -g -version=Strict "location/to/filter_spirit/file.txt" "location/to/filter/filter.filter"

Which then would change all the lines that has the @Strict(x) with was on the line before. So in the example above it would simply change "Show" to "Hide".

You could also have that function add an action if there the line is empty without the @Strict command beeing called. Like this:

BaseType ["Vaal Axe", "Coronal Maul", "Exquisite Blade"]{
    SetBackgroundColor color_rare_t3
    SetFontSize font_t5
    SetBorderColor color_rare_border_t3
    @Strict(DisableDropSound True)
    @Strict(Hide) Show
}

Which when compiled with the "-version=Strict" [option] shown above would change the block from "Show" to "Hide" and add the "DisableDropSound" "True" to the block as well.

What do you think about this idea for implementing strictness versioning?

You also want to be able to add the PlayDefaultDropSound = False to any block that is tagged with

Alekhoff avatar Dec 13 '19 16:12 Alekhoff

I don't like this approach, for these reasons:

  • There are not 2 states, but 3 (generate with Show, generate with Hide, do not generate). In a lot of cases you want the 3rd one - the difference is that items not explicitly hidden may be caught by later blocks. For example:
    • You want to hide armourer scraps and whetstones, simply because you don't pick up them and they have no other use.
    • You don't want to hide hammers when you resign from hammer recipe. You want to just not generate a block for them so they can still be catched by chromatic or chaos recipe blocks.
  • The syntax: the same block will likely be used in multiple variants and each variant can use multiple blocks. So it's an n:n relation, which support can be realized in 2 ways (example syntax):
    • block specifies to which variants it belongs: Show @Strict(Show) @UberStrict(Hide)
    • variant specifies which block it uses: @Strict = { currency, misc, maps, ... } @UberStrict = { ... }

The second strictness approach appeals more to me, because:

  • You can freely compose variants from existing blocks or sets of nested blocks
  • It implicitly supports "do not generate" state, you simply don't include unwanted blocks in the variant
  • You care more about variants which use specific blocks, rather than which blocks are where used.

I have updated the issue intial comment to better outline what is the goal of the feature. This should help in designing it and give a direction for propositions.

Xeverous avatar Dec 19 '19 11:12 Xeverous

Another idea: each block could be marked with a tag and then one could form multiple variants from tags:

@lab
BaseType "Offering to the Goddess" {

...

normal = { +currency, +shards, +lab, +rares, +crafting, ... }
strict = { +currency, +lab, -rares, ... }

pros:

  • It allows easy composition (+ generating with Show, - - Hide, nothing - not generating)

cons:

  • If there are any blocks without a tag, they could be assumed to be always generated but ... their order in the output is unknown. So we either require the user to mark every block or implement complex rules behind generation of untagged blocks.

Xeverous avatar Dec 22 '19 08:12 Xeverous

A bit of thinking and I actually prefer your idea of @Strict(Hide) Show - I see the potential to satisfy all conditions:

  • Support for 3 states (need to think about the syntax/keyword name for do-not-generate but it's definitely possible).
  • Avoids code duplication (you just change show/hide/do-not-generate).
  • Minimal extra syntax, the variant name is already specified in the syntax.
  • Each block is independent.
  • We can still leave current Show, Hide syntax - a thing that I very like - a user who does not want/need variants can just write the filter as it is now (now forced usage of variant-specific syntax) - untagged blocks will be generated as-is in all variants.

We only need an idea of better syntax, something that will allow to write one Show/Hide keyword for multiple variants.

Xeverous avatar Dec 22 '19 08:12 Xeverous

Been away for Christmas, but i really like that you came back to this idea. It makes it so there will be minimal effort to convert current filters to work with it.

I think it could work really well i this instance, just need to figure out a good syntax.

Alekhoff avatar Dec 29 '19 16:12 Alekhoff

Adding label and pinning for awarness. We need more ideas for the variant support, perhaps someone with experience in other languages could help.

We basically need:

  • an optional syntax which is not required (existing filter templates should continue to work)
  • support for 3 states of the generation (generate with Show, generate with Hide, do not generate)
  • a way to nest variant tags or conveniently specify which filter variant should use which blocks
  • some way to specify output file name or map it to the variant name

The current idea of something like @strict(..code...) can satisfy first 3 points, but gets messy when:

  • you want multiple variants to use the same code
  • you want 1 variant to use block X and 1 variant to use only block Y which is a subblock of X

Xeverous avatar Jan 23 '20 12:01 Xeverous

I'm still uncertain on this and GGG just relased a big filters improvement annoucement - https://www.pathofexile.com/forum/view-thread/2771031

However, I have been fiddling with the grammar to also support loading/debugging real filters and started to think about rewriting FS grammar so that it is as close to real filters as possible. I won't remove $,{} etc but mostly I want to get rid of the stuff like color = RGB(255, 255, 255) so that one can actually just write color = 255 255 255.

The only ambiguity I have found is when someone would write x = 123 123 123 y or x = "base1" "base2" y - the parser would not know whether that y is a variable describing some opacity/base or a part of further y = ... code. It can be worked around with a rule that requires a line break before any next definition, which I think is fine since most people will probably be used to 1-thing-per-line. So far the only drawback of introducing line breaks into the grammar is that it will no longer be possible to write Class "abc" "def" ... "xyz" where the names are split across multiple lines. This however could use another workaround - programming languages which have something that is per-line allow to use \ at the end of it to indicate that the line is continued below. This would looks in FS this way:

BaseType "abc" "def" \
    "xyz" \
    "zzzz" \
    "last base type name"

Xeverous avatar Feb 12 '20 20:02 Xeverous

Ok, this took a while, but it is finally done.

  • Dynamic visibility statement: (ShowHide $value and ShowDiscard $value) - 4aaa4a7500b0d8bdf668ca6e1b717fccdbeac3a1
  • Expand $subtree feature - 440e8b99f1cd4704999363a03e6bddebcd25e952
  • documentation for these 2 (with examples) - 3d2dad8bbbedb46de208e833fe51699f30e03bdb

I won't explain it here in detail (just read documentation) but I think it's the best implementation possible that satisfies all of my goals for finely-grained strictness editing. I have even added some reasoning to the documentation.

Xeverous avatar Apr 14 '21 22:04 Xeverous