pyfa-org / eos

Eos - library for modeling EVE online ship fits
GNU Lesser General Public License v3.0
60 stars 19 forks source link

Boosters #20

Closed DarkFenX closed 7 years ago

DarkFenX commented 8 years ago

Need to implement:

DarkFenX commented 8 years ago

Started implementation in the boosters branch

DarkFenX commented 8 years ago

Regarding booster side-effect detection. First, i will describe how it works.

Each effect entry in database has fittingUsageChanceAttributeID. When item is 'added to fit' (booster being consumed in this case), each effect looks up for a value of this attribute. This value is a chance of applying said effect.

I'll show an example.

Item: Strong Crash Booster (typeID 10152)
Effect: boosterMaxVelocityPenalty (effectID 2746)
    fittingUsageChanceAttributeID: boosterEffectChance2 (attributeID 1090)
    Modifiers 1:
        Source attribute: boosterMaxVelocityPenalty (attributeID 1151)
        Target attribute: maxVelocity (attributeID 37)
Attributes:
    boosterMaxVelocityPenalty (attributeID 1151) -30.0  # Display name "Velocity Penalty"
    boosterEffectChance2 (attributeID 1090) 0.4  # No display name

effect boosterMaxVelocityPenalty uses value of boosterEffectChance2 attribute to define chance of getting this side-effect (40% base). Modifiers on this effect refer boosterMaxVelocityPenalty attribute (strength of modification) and maxVelocity (target attribute for modification). For eos, we have 2 options.

1) Expose just map {effect ID: chance of this effect happening}. This is not very useful for UI - such data does not provide user-friendly hint of what's being penalized. This data can be fetched by investigating effect's modifiers and fetching source attribute (just boosterMaxVelocityPenalty in this case). Name of this attribute (Velocity Penalty) makes sense to the user. We can do it in service layer.

2) Expose map {effect ID: (chance of this effect happening, [list of modifier's source attribute IDs])}. We do what i just described above, but in eos.

What makes me feel uncomfortable about 1), is that service has to mess with modifiers (which are more or less low-level stuff of eos, still exposed though). What makes me feel uncomfortable about 2), is that eos has to expose shit just because it's needed for names on the UI side, and eos generally doesn't care about it at all.

What do you prefer?

Ebag333 commented 8 years ago

So we have two things going on here.

First off, exposing to the end user what there is. There's already information given between the description, attributes, and effects. It's rather clunky (thanks CCP for that) but users are already used to it because it's what they see in game. (We do a pretty decent job of exposing it in Pyfa, MUCH better than in game. It's not perfect by any means.)

For 1 vs 2, I would lean more toward Eos not exposing things that the service layer can look up. The service layer has all the data Eos does (and then some). I agree that the service layer shouldn't be doing Eos level stuff, but it is a good place to put obscure connections between objects (like modes and T3D hulls). The way CCP laid out the data (using attributes and effects) is great for calculation purposes, terrible for UI purposes, so the UI devs might end up hard coding a mapping anyway.

TL;DR, I think this is a problem better solved on the UI/service side and not have Eos doing stuff not fitting calc related solely for the purpose of making UI easier to do.

. Second is toggling the booster side effects. As discussed in Slack, the code is already written so that it's essentially a global thing (not just limited to boosters), and I think that would be extremely useful, especially for our purposes with testing.

If we provide a way to selectively turn on/off specific effects as part of a fit, then the UI/Service can simply pass in a list of effects that the end user selected to disable/enable. Not only does this let us turn on/off boosters, but it lets us turn on/off effects for anything. More a UI discussion but could be as simple as a toggle on the effects tab.

Currently there's no good way to do this in Pyfa (short of hacking the effect file) so this would be extremely useful for testing.

DarkFenX commented 8 years ago

Ideal API exposed by pyfa's service would be:

@property
Booster.side_effects:
    return set(SideEffects)

SideEffect:
    name (exposed name of penalizing attribute)
    chance (float, calculated value of chance attrib)
    status (true/false, with ability to set it)
    __effect_id (for internal use, to fetch modifiers and other stuff from eos)

Name is rather complex, as i mentioned. You have to make sure following cases are handled:

For Eos booster API, I have several variants.

1) Fancy:

@property
Booster.side_effects
    return set(SideEffects)

SideEffect:
    effect_id (for reference, to which effect this side-effect belongs)
    chance (float, calculated value of chance attrib)
    status (true/false, with ability to set it)

However, it might be hard to track additional objects - as they need to ba handled somehow on other operations (e.g. fit source switch, booster detaching from fit, booster attaching to fit, maybe there's more). Easier for implementation.

2) Bug-proof, easy to implement:

@property
Booster.side_effects
    return {effect: namedtuple(chance, status)}

Booster.set_side_effect_status(effect, status)

I thought fancy one would be more convenient, but the more i think about it the more i like 2nd variant, mostly because it's much less error-prone.

DarkFenX commented 8 years ago

Following things are yet to be done:

1) Expose side-effect controls to Boosters (with check that it's actual side-effect) 2) Add ability to randomize chance-based effects based on chance values (on Holder class) 3) Write tests

DarkFenX commented 8 years ago

Check boosters branch for implementation. Only tests and maybe some bug fixes are needed to close this ticket.

DarkFenX commented 7 years ago

Merged into master