Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using Pyfa as backend for calculating a fit's stats #1212

Closed
dancodes opened this issue Jun 2, 2017 · 6 comments
Closed

Using Pyfa as backend for calculating a fit's stats #1212

dancodes opened this issue Jun 2, 2017 · 6 comments
Labels
discussion This is mostly a discussion thread

Comments

@dancodes
Copy link

dancodes commented Jun 2, 2017

Hello, question here:

I'd like to make my own command line application that can calculate a ship's stats (say, DPS) given a fit.

  • Is there a library in Pyfa's code that's separated from the front end so I can do this?
  • What class represents a ship with modules and rigs attached to it? Do I need another class to calculate its stats?

I'm not looking for a completely modular library, just some guidance in Pyfa's current codebase so I can cherry pick what I want, even if it involves having the whole repository on my working folder.

Thanks!

@blitzmann
Copy link
Collaborator

Hi there,

There is no external library that pyfa uses for it's calculations. Its engine is called eos and can be found in the root project directory. I try to keep eos completely separate from the rest of the project, so there isn't anything in pyfa that eos depends on, and it should be able to run standalone.

You'll have to know some basic structure. There's two different databases - one for EVE data, and one for user data. EVE data is found in /eve.db, while user data is defaulted to /saveddata/saveddata.db (when importing eos directly) but that path can be changed if needed (some config options are in eos/config.py).

eos/gamedata.py is where we define the EVE data models (Items, Attributes, Effects, etc). These represent entities in the EVE database. /eos/saveddata/ is where the various user classes are stored, and represent entities in the users database. They usually are wrappers around EVE objects. For example, gamedata.py defines Item which is a generic item in the database. It has a list of attributes, effects, etc (relationships are handled by the ORM, SQLAlchemy). However, an item can be a ship, module, drone, etc. Those are defined as user objects. So, to get a Module from an item (with all methods of a module), you do Module(item). Same with drone, fighter, ship, etc. Fit is the all encompassing object that links them all together.

Sample script:

import eos
import eos.db
from eos.gamedata import *
from eos.saveddata.ship import Ship
from eos.saveddata.module import Module
from eos.saveddata.fit import Fit
from eos.saveddata.module import State
import eos.db.gamedata.queries as queries
import eos.db.saveddata.queries as s_queries

# lets get a few base things first
# Instead of getItem, you can access it via eos.db.gamedata_session.query(Item).filter(Item.name == 'Rifter').first()
# This is basically what getItem() does
iRifter = queries.getItem('Rifter') # Get Rifter
iMWD = queries.getItem('5MN Microwarpdrive I') # get MWD

# pyfa comes with two static characters, all 5 and all 0
cAll5 = s_queries.getCharacter('All 5')
cAll0 = s_queries.getCharacter('All 0')

print "Rifter: ", iRifter
print "MWD: ", iMWD

print "Rifters attributes: ", iRifter.attributes  # print attributes of item

# print (base) value of speed.
# You can also do iRifter.getAttribute('maxVelocity')
print "Max Velocity: ", iRifter.attributes['maxVelocity'].value

# convert the items to their proper classes
ship = Ship(iRifter)
mod = Module(iMWD)  # defaults to online state

print ship
print mod

fit = Fit(ship, "Test Rifter Fit") # Create fit
fit.character = cAll5 # set character to all 5
fit.modules.append(mod) # add module to the fit

print repr(fit)

print "="*20

# The other ways of getting attributes will only get the base attributes, not the calculated value. getModifiedItemAttr
# is a method on the wrapper classes that allows you to get the value of an attribute including any modification applied
# Since we haven't calculated this fitting yet, this will return the base value

print "Base velocity: ", fit.ship.getModifiedItemAttr('maxVelocity')

# Calculate the fit. Since the MWD is not yet "Active", only online, it will not apply, but character skills will

fit.calculateModifiedAttributes() # calculate fit along with character skills

print "Modified velocity: ", fit.ship.getModifiedItemAttr('maxVelocity')

mod.state = State.ACTIVE

fit.calculateModifiedAttributes() # calculate fit along with character skills

print "Modified velocity (with MWD): ", fit.ship.getModifiedItemAttr('maxVelocity')

fit.character = cAll0

fit.calculateModifiedAttributes() # calculate fit along with character skills

print "Modified with MWD and All0 character: ", fit.ship.getModifiedItemAttr('maxVelocity')

# At this point, the fit is not saved in the database and does not have an ID

print "Fit ID before save: {}".format(fit.ID)

# save it
eos.db.commit()

print "Fit ID after save: {}".format(fit.ID)

# to get a fit from the database

fit2 = s_queries.getFit(2) # whatever fitID you want

print repr(fit2)

output:

Rifter:  Item(ID=587, name=Rifter) at 0x3a3ce90
MWD:  Item(ID=434, name=5MN Microwarpdrive I) at 0x3c49170
Rifters attributes:  {u'cpuOutput': <eos.gamedata.Attribute object at 0x03DAA650>, u'warpCapacitorNeed': <eos.gamedata.Attribute object at 0x03DAAE70>, u'turretSlotsLeft': <eos.gamedata.Attribute object at 0x03DAA990>, u'shipBonusMF2': <eos.gamedata.Attribute object at 0x03DB3E50>, u'heatDissipationRateMed': <eos.gamedata.Attribute object at 0x03C65230>, u'heatCapacityHi': <eos.gamedata.Attribute object at 0x03C65DD0>, u'heatCapacityLow': <eos.gamedata.Attribute object at 0x03C4F4B0>, u'powerOutput': <eos.gamedata.Attribute object at 0x03CFD810>, u'shieldEmDamageResonance': <eos.gamedata.Attribute object at 0x03DB3450>, u'heatCapacityMed': <eos.gamedata.Attribute object at 0x03C4F250>, u'capacitorCapacity': <eos.gamedata.Attribute object at 0x03DB39F0>, u'scanSpeed': <eos.gamedata.Attribute object at 0x03DAA890>, u'maxPassengers': <eos.gamedata.Attribute object at 0x03DAAD30>, u'rigSize': <eos.gamedata.Attribute object at 0x03E24610>, u'shipBonusMF': <eos.gamedata.Attribute object at 0x03DB38B0>, u'gfxBoosterID': <eos.gamedata.Attribute object at 0x03D9E190>, u'shieldThermalDamageResonance': <eos.gamedata.Attribute object at 0x03DB3630>, u'maxTargetRange': <eos.gamedata.Attribute object at 0x03DAA810>, u'armorThermalDamageResonance': <eos.gamedata.Attribute object at 0x03DB33B0>, u'shieldCapacity': <eos.gamedata.Attribute object at 0x03D9E5D0>, u'lowSlots': <eos.gamedata.Attribute object at 0x03DAA1F0>, u'shieldUniformity': <eos.gamedata.Attribute object at 0x03DB3A90>, u'typeColorScheme': <eos.gamedata.Attribute object at 0x03E24750>, u'radius': <eos.gamedata.Attribute object at 0x03DAAFB0>, u'scanMagnetometricStrength': <eos.gamedata.Attribute object at 0x03C65F90>, u'shieldExplosiveDamageResonance': <eos.gamedata.Attribute object at 0x03DB34F0>, u'capacity': <eos.gamedata.Attribute object at 0x03DAA150>, u'droneCapacity': <eos.gamedata.Attribute object at 0x03DB3770>, u'powerToSpeed': <eos.gamedata.Attribute object at 0x03DAA450>, u'requiredSkill1Level': <eos.gamedata.Attribute object at 0x03DB36D0>, u'hullKineticDamageResonance': <eos.gamedata.Attribute object at 0x03D9E150>, u'armorHP': <eos.gamedata.Attribute object at 0x03DB3150>, u'techLevel': <eos.gamedata.Attribute object at 0x03DB3810>, u'upgradeSlotsLeft': <eos.gamedata.Attribute object at 0x03DAA170>, u'shieldKineticDamageResonance': <eos.gamedata.Attribute object at 0x03DB3590>, u'fwLpKill': <eos.gamedata.Attribute object at 0x03E246B0>, u'heatAttenuationLow': <eos.gamedata.Attribute object at 0x03E24430>, u'baseWarpSpeed': <eos.gamedata.Attribute object at 0x03E24570>, u'maxVelocity': <eos.gamedata.Attribute object at 0x03DAA550>, u'scanLadarStrength': <eos.gamedata.Attribute object at 0x03C65E70>, u'upgradeCapacity': <eos.gamedata.Attribute object at 0x03DAA2F0>, u'medSlots': <eos.gamedata.Attribute object at 0x03DAA230>, u'maxLockedTargets': <eos.gamedata.Attribute object at 0x03C65BD0>, u'thermalDamageResonance': <eos.gamedata.Attribute object at 0x03DAAAB0>, u'shipScanResistance': <eos.gamedata.Attribute object at 0x03DB3B30>, u'heatAttenuationHi': <eos.gamedata.Attribute object at 0x03E24230>, u'heatAttenuationMed': <eos.gamedata.Attribute object at 0x03E24390>, u'explosiveDamageResonance': <eos.gamedata.Attribute object at 0x03DAAB50>, u'scanResolution': <eos.gamedata.Attribute object at 0x03DB3DB0>, u'hiSlots': <eos.gamedata.Attribute object at 0x03DAA0B0>, u'scanRadarStrength': <eos.gamedata.Attribute object at 0x03C653F0>, u'kineticDamageResonance': <eos.gamedata.Attribute object at 0x03DAAA10>, u'emDamageResonance': <eos.gamedata.Attribute object at 0x03DAABF0>, u'uniformity': <eos.gamedata.Attribute object at 0x03DAADD0>, u'cpuLoad': <eos.gamedata.Attribute object at 0x03DAA6D0>, u'hullExplosiveDamageResonance': <eos.gamedata.Attribute object at 0x03D9E1F0>, u'hullEmDamageResonance': <eos.gamedata.Attribute object at 0x03E24190>, u'heatDissipationRateHi': <eos.gamedata.Attribute object at 0x03C65C30>, u'heatGenerationMultiplier': <eos.gamedata.Attribute object at 0x03C4F330>, u'agility': <eos.gamedata.Attribute object at 0x03DAA790>, u'launcherSlotsLeft': <eos.gamedata.Attribute object at 0x03DAA910>, u'hp': <eos.gamedata.Attribute object at 0x03CFD890>, u'armorExplosiveDamageResonance': <eos.gamedata.Attribute object at 0x03DB3270>, u'volume': <eos.gamedata.Attribute object at 0x03D9EA90>, u'armorUniformity': <eos.gamedata.Attribute object at 0x03DB3BD0>, u'metaLevel': <eos.gamedata.Attribute object at 0x03DB3F90>, u'powerLoad': <eos.gamedata.Attribute object at 0x03DAA3D0>, u'droneBandwidth': <eos.gamedata.Attribute object at 0x03E244D0>, u'mainColor': <eos.gamedata.Attribute object at 0x03DAAC90>, u'minTargetVelDmgMultiplier': <eos.gamedata.Attribute object at 0x03E240F0>, u'maxDirectionalVelocity': <eos.gamedata.Attribute object at 0x03E24050>, u'hullThermalDamageResonance': <eos.gamedata.Attribute object at 0x03D9E3B0>, u'rechargeRate': <eos.gamedata.Attribute object at 0x03DAA730>, u'damage': <eos.gamedata.Attribute object at 0x03CFD9F0>, u'rigSlots': <eos.gamedata.Attribute object at 0x03DAA350>, u'propulsionGraphicID': <eos.gamedata.Attribute object at 0x03D9E3F0>, u'signatureRadius': <eos.gamedata.Attribute object at 0x03DB3D10>, u'shieldRechargeRate': <eos.gamedata.Attribute object at 0x03DB3950>, u'armorEmDamageResonance': <eos.gamedata.Attribute object at 0x03DB31D0>, u'structureUniformity': <eos.gamedata.Attribute object at 0x03DB3C70>, u'armorKineticDamageResonance': <eos.gamedata.Attribute object at 0x03DB3310>, u'requiredSkill1': <eos.gamedata.Attribute object at 0x03C65C70>, u'heatDissipationRateLow': <eos.gamedata.Attribute object at 0x03C49FD0>, u'warpFactor': <eos.gamedata.Attribute object at 0x03DAA4D0>, u'scanGravimetricStrength': <eos.gamedata.Attribute object at 0x03D9E0B0>, u'mass': <eos.gamedata.Attribute object at 0x03C4FA10>, u'warpSpeedMultiplier': <eos.gamedata.Attribute object at 0x03DB3EF0>}
Max Velocity:  365.0
Ship(ID=587, name=Rifter) at 0x3d9ebf0
Module(ID=434, name=5MN Microwarpdrive I) at 0x3c4fbd0
Fit(ID=None, ship=Rifter, name=Test Rifter Fit) at 0x38c3fd0
====================
Base velocity:  365.0
Modified velocity:  456.25
Modified velocity (with MWD):  3185.88864071
Modified with MWD and All0 character:  2111.96873006
Fit ID before save: None
Fit ID after save: 4184
None

If you have any querstions about this stuff or how it works, please feel free to reach out to me on pyfa's Slack (invite: https://pyfainvite.azurewebsites.net/). it's best to chat about it realtime rather than go back and forth over github issue comments :)

@dancodes
Copy link
Author

dancodes commented Jun 4, 2017

Wow, this is a top notch answer and way more than I asked for - I would have needed to look for how to do what you did eventually. You've truly saved me from hours of figuring out how it all works and I really appreciate it. Make sure this ends up in a wiki somehow, this is worthy of a page of its own.

Thanks again.

@blitzmann
Copy link
Collaborator

@dancodes thanks! That's a good point - I'll try to spruce up a wiki article on this :)

@Ebag333
Copy link
Contributor

Ebag333 commented Jun 6, 2017

There is a much easier way.

Take a look at the tests and what I did for that. You literally just have to import and reference the DB object and it does all the work for you.

@blitzmann
Copy link
Collaborator

Or you can do that. It's basically doing the same thing our old all encompassing importer did that we removed during the refactor (eos/types.py importing all the things we need in one place, and referencing that elsewhere). That saves having to import the various things in different places, just import that one thing and use it, with the only real difference I see being that the imports happen in a function call which returns a collection of them. Makes it easy to make a single call to get the collection of Classes.

@dancodes The method the tests use save on import statements to get to the classes. Personally I feel if you're looking to integrate pyfa's engine into another application, importing the things that you need when needed directly from eos is the best way to go. That also cuts out a middle man so that the IDE can be of more use since you would be importing the module directly rather than key off a dictionary. But you could go either way; doesn't really matter how you get the classes as long as you get to them somehow. And of course, regardless of how you get the classes, you still need to create the instances, add modules, calculate, save to db, etc etc. :)

@blitzmann blitzmann added the discussion This is mostly a discussion thread label May 28, 2018
@blitzmann
Copy link
Collaborator

Closing this as it was mostly a discussion thread, trying to clean up some of the older issues. Thanks for the inquiry @dancodes!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion This is mostly a discussion thread
Projects
None yet
Development

No branches or pull requests

3 participants