Merge remote-tracking branch 'origin/master' into blitzmann_CIUpdates

# Conflicts:
#	dist_assets/mac/pyfa.spec
This commit is contained in:
Ryan Holmes
2019-02-17 15:52:57 -05:00
47 changed files with 473 additions and 124 deletions

View File

@@ -22,6 +22,7 @@ from xml.dom import minidom
from logbook import Logger
from eos.saveddata.price import PriceStatus
from service.network import Network
from service.price import Price, TIMEOUT, VALIDITY
@@ -52,6 +53,7 @@ class EveMarketData(object):
price = float(type_.firstChild.data)
except (TypeError, ValueError):
pyfalog.warning("Failed to get price for: {0}", type_)
continue
# Fill price data
priceobj = priceMap[typeID]
@@ -61,11 +63,10 @@ class EveMarketData(object):
if price != 0:
priceobj.price = price
priceobj.time = time.time() + VALIDITY
priceobj.status = PriceStatus.success
else:
priceobj.time = time.time() + TIMEOUT
priceobj.failed = None
# delete price from working dict
del priceMap[typeID]

View File

@@ -22,13 +22,14 @@ from xml.dom import minidom
from logbook import Logger
from eos.saveddata.price import PriceStatus
from service.network import Network
from service.price import Price, VALIDITY
pyfalog = Logger(__name__)
class EveCentral(object):
class EveMarketer(object):
name = "evemarketer"
@@ -61,10 +62,10 @@ class EveCentral(object):
priceobj = priceMap[typeID]
priceobj.price = percprice
priceobj.time = time.time() + VALIDITY
priceobj.failed = None
priceobj.status = PriceStatus.success
# delete price from working dict
del priceMap[typeID]
Price.register(EveCentral)
Price.register(EveMarketer)

View File

@@ -1,13 +1,8 @@
import inspect
import os
import platform
import re
import sys
import traceback
import json
import eos.db
from math import log
from numbers import Number
from config import version as pyfaVersion
from service.fit import Fit
from service.market import Market
@@ -15,9 +10,11 @@ from eos.enum import Enum
from eos.saveddata.module import Hardpoint, Slot, Module, State
from eos.saveddata.drone import Drone
from eos.effectHandlerHelpers import HandledList
from eos.db import gamedata_session, getItemsByCategory, getCategory, getAttributeInfo, getGroup
from eos.gamedata import Category, Group, Item, Traits, Attribute, Effect, ItemEffect
from eos.db import gamedata_session, getCategory, getAttributeInfo, getGroup
from eos.gamedata import Attribute, Effect, Group, Item, ItemEffect
from eos.utils.spoolSupport import SpoolType, SpoolOptions
from gui.fitCommands.calc.fitAddModule import FitAddModuleCommand
from gui.fitCommands.calc.fitRemoveModule import FitRemoveModuleCommand
from logbook import Logger
pyfalog = Logger(__name__)
@@ -30,9 +27,9 @@ class RigSize(Enum):
CAPITAL = 4
class EfsPort():
class EfsPort:
wepTestSet = {}
version = 0.02
version = 0.03
@staticmethod
def attrDirectMap(values, target, source):
@@ -72,12 +69,12 @@ class EfsPort():
if propID is None:
return None
sFit.appendModule(fitID, propID)
FitAddModuleCommand(fitID, propID).Do()
sFit.recalc(fit)
fit = eos.db.getFit(fitID)
mwdPropSpeed = fit.maxSpeed
mwdPosition = list(filter(lambda mod: mod.item and mod.item.ID == propID, fit.modules))[0].position
sFit.removeModule(fitID, mwdPosition)
FitRemoveModuleCommand(fitID, [mwdPosition]).Do()
sFit.recalc(fit)
fit = eos.db.getFit(fitID)
return mwdPropSpeed
@@ -115,6 +112,9 @@ class EfsPort():
"Titan Phenomena Generator", "Non-Repeating Hardeners"
]
projectedMods = list(filter(lambda mod: mod.item and mod.item.group.name in modGroupNames, fit.modules))
# Sort projections to prevent the order needlessly changing as pyfa updates.
projectedMods.sort(key=lambda mod: mod.item.ID)
projectedMods.sort(key=lambda mod: mod.item.group.ID)
projections = []
for mod in projectedMods:
maxRangeDefault = 0
@@ -191,7 +191,7 @@ class EfsPort():
return projections
# Note that unless padTypeIDs is True all 0s will be removed from modTypeIDs in the return.
# They always are added initally for the sake of brevity, as this option may not be retained long term.
# They always are added initially for the sake of brevity, as this option may not be retained long term.
@staticmethod
def getModuleInfo(fit, padTypeIDs=False):
moduleNames = []
@@ -303,9 +303,9 @@ class EfsPort():
def getWeaponSystemData(fit):
weaponSystems = []
groups = {}
# TODO: fetch spoolup option
# Export at maximum spool for consistency, spoolup data is exported anyway.
defaultSpoolValue = 1
spoolOptions = SpoolOptions(SpoolType.SCALE, defaultSpoolValue, False)
spoolOptions = SpoolOptions(SpoolType.SCALE, defaultSpoolValue, True)
for mod in fit.modules:
if mod.getDps(spoolOptions=spoolOptions).total > 0:
# Group weapon + ammo combinations that occur more than once
@@ -344,7 +344,7 @@ class EfsPort():
aoeFieldRange = stats.getModifiedItemAttr("empFieldRange")
# This also covers non-bomb weapons with dps values and no hardpoints, most notably targeted doomsdays.
typeing = "SmartBomb"
# Targeted DDs are the only non drone/fighter weapon without an explict max range
# Targeted DDs are the only non drone/fighter weapon without an explicit max range
if stats.item.group.name == 'Super Weapon' and stats.maxRange is None:
maxRange = 300000
else:
@@ -515,7 +515,7 @@ class EfsPort():
# Since the effect modules are fairly opaque a mock test fit is used to test the impact of traits.
# standin class used to prevent . notation causing issues when used as an arg
class standin():
class standin:
pass
tf = standin()
tf.modules = HandledList(turrets + launchers)
@@ -551,7 +551,7 @@ class EfsPort():
@staticmethod
def getShipSize(groupID):
# Size groupings are somewhat arbitrary but allow for a more managable number of top level groupings in a tree structure.
# Size groupings are somewhat arbitrary but allow for a more manageable number of top level groupings in a tree structure.
frigateGroupNames = ["Frigate", "Shuttle", "Corvette", "Assault Frigate", "Covert Ops", "Interceptor",
"Stealth Bomber", "Electronic Attack Ship", "Expedition Frigate", "Logistics Frigate"]
destroyerGroupNames = ["Destroyer", "Interdictor", "Tactical Destroyer", "Command Destroyer"]
@@ -625,9 +625,29 @@ class EfsPort():
}
resonance = {"hull": hullResonance, "armor": armorResonance, "shield": shieldResonance}
shipSize = EfsPort.getShipSize(fit.ship.item.groupID)
# TODO: fetch spoolup option
# Export at maximum spool for consistency, spoolup data is exported anyway.
defaultSpoolValue = 1
spoolOptions = SpoolOptions(SpoolType.SCALE, defaultSpoolValue, False)
spoolOptions = SpoolOptions(SpoolType.SCALE, defaultSpoolValue, True)
def roundNumbers(data, digits):
if isinstance(data, str):
return
if isinstance(data, dict):
for key in data:
if isinstance(data[key], Number):
data[key] = round(data[key], digits)
else:
roundNumbers(data[key], digits)
if isinstance(data, list) or isinstance(data, tuple):
for val in data:
roundNumbers(val, digits)
if isinstance(data, Number):
rounded = round(data, digits)
if data != rounded:
pyfalog.error("Error rounding numbers for EFS export, export may be inconsistent."
"This suggests the format has been broken somewhere.")
return
try:
dataDict = {
"name": fitName, "ehp": fit.ehp, "droneDPS": fit.getDroneDps().total,
@@ -650,9 +670,12 @@ class EfsPort():
"modTypeIDs": modTypeIDs, "moduleNames": moduleNames,
"pyfaVersion": pyfaVersion, "efsExportVersion": EfsPort.version
}
except TypeError:
# Recursively round any numbers in dicts to 6 decimal places.
# This prevents meaningless rounding errors from changing the output whenever pyfa changes.
roundNumbers(dataDict, 6)
except TypeError as e:
pyfalog.error("Error parsing fit:" + str(fit))
pyfalog.error(TypeError)
pyfalog.error(e)
dataDict = {"name": fitName + "Fit could not be correctly parsed"}
export = json.dumps(dataDict, skipkeys=True)
return export

View File

@@ -26,6 +26,7 @@ import wx
from logbook import Logger
from eos import db
from eos.saveddata.price import PriceStatus
from service.fit import Fit
from service.market import Market
from service.network import TimeoutError
@@ -85,13 +86,18 @@ class Price(object):
toRequest = set()
# Compose list of items we're going to request
for typeID in priceMap:
for typeID in tuple(priceMap):
# Get item object
item = db.getItem(typeID)
# We're not going to request items only with market group, as eve-central
# doesn't provide any data for items not on the market
if item is not None and item.marketGroupID:
toRequest.add(typeID)
if item is None:
continue
if not item.marketGroupID:
priceMap[typeID].status = PriceStatus.notSupported
del priceMap[typeID]
continue
toRequest.add(typeID)
# Do not waste our time if all items are not on the market
if len(toRequest) == 0:
@@ -117,11 +123,10 @@ class Price(object):
except TimeoutError:
# Timeout error deserves special treatment
pyfalog.warning("Price fetch timout")
for typeID in priceMap.keys():
for typeID in tuple(priceMap):
priceobj = priceMap[typeID]
priceobj.time = time.time() + TIMEOUT
priceobj.failed = True
priceobj.status = PriceStatus.fail
del priceMap[typeID]
except Exception as ex:
# something happened, try another source
@@ -134,7 +139,7 @@ class Price(object):
for typeID in priceMap.keys():
priceobj = priceMap[typeID]
priceobj.time = time.time() + REREQUEST
priceobj.failed = True
priceobj.status = PriceStatus.fail
@classmethod
def fitItemsList(cls, fit):
@@ -172,8 +177,8 @@ class Price(object):
def getPrices(self, objitems, callback, waitforthread=False):
"""Get prices for multiple typeIDs"""
requests = []
sMkt = Market.getInstance()
for objitem in objitems:
sMkt = Market.getInstance()
item = sMkt.getItem(objitem)
requests.append(item.price)
@@ -197,6 +202,7 @@ class Price(object):
class PriceWorkerThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.name = "PriceWorker"

View File

@@ -525,6 +525,7 @@ class ContextMenuSettings(object):
"tacticalMode" : 1,
"targetResists" : 1,
"whProjector" : 1,
"moduleFill" : 1,
}
self.ContextMenuDefaultSettings = SettingsProvider.getInstance().getSettings("pyfaContextMenuSettings", ContextMenuDefaultSettings)