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

This commit is contained in:
Ryan Holmes
2018-11-27 23:59:22 -05:00
175 changed files with 3653 additions and 336 deletions

View File

@@ -210,8 +210,10 @@ class Market(object):
"Fiend" : self.les_grp, # AT13 prize
"Caedes" : self.les_grp, # AT14 prize
"Rabisu" : self.les_grp, # AT14 prize
"Victor" : self.les_grp, # AT prize
"Virtuoso" : self.les_grp, # AT prize
"Victor" : self.les_grp, # AT15 prize
"Virtuoso" : self.les_grp, # AT15 prize
"Hydra" : self.les_grp, # AT16 prize
"Tiamat" : self.les_grp, # AT16 prize
}
self.ITEMS_FORCEGROUP_R = self.__makeRevDict(self.ITEMS_FORCEGROUP)

View File

@@ -22,7 +22,7 @@ import re
from logbook import Logger
from eos.db.gamedata.queries import getAttributeInfo, getDynamicItem
from eos.db.gamedata.queries import getDynamicItem
from eos.saveddata.cargo import Cargo
from eos.saveddata.citadel import Citadel
from eos.saveddata.booster import Booster
@@ -32,10 +32,10 @@ from eos.saveddata.implant import Implant
from eos.saveddata.module import Module, State, Slot
from eos.saveddata.ship import Ship
from eos.saveddata.fit import Fit
from gui.utils.numberFormatter import roundToPrec
from service.fit import Fit as svcFit
from service.market import Market
from service.port.shared import IPortUser, processing_notify
from service.port.muta import parseMutant, renderMutant
from service.port.shared import IPortUser, fetchItem, processing_notify
from enum import Enum
@@ -157,17 +157,7 @@ def exportEft(fit, options):
if mutants and options & Options.MUTATIONS.value:
for mutantReference in sorted(mutants):
mutant = mutants[mutantReference]
mutatedAttrs = {}
for attrID, mutator in mutant.mutators.items():
attrName = getAttributeInfo(attrID).name
mutatedAttrs[attrName] = mutator.value
mutationLines.append('[{}] {}'.format(mutantReference, mutant.baseItem.name))
mutationLines.append(' {}'.format(mutant.mutaplasmid.item.name))
# Round to 7th significant number to avoid exporting float errors
customAttrsLine = ', '.join(
'{} {}'.format(a, roundToPrec(mutatedAttrs[a], 7))
for a in sorted(mutatedAttrs))
mutationLines.append(' {}'.format(customAttrsLine))
mutationLines.append(renderMutant(mutant, firstPrefix='[{}] '.format(mutantReference), prefix=' '))
if mutationLines:
sections.append('\n'.join(mutationLines))
@@ -507,59 +497,48 @@ def _importPrepareString(eftString):
return lines
mutantHeaderPattern = re.compile('^\[(?P<ref>\d+)\](?P<tail>.*)')
def _importGetMutationData(lines):
data = {}
# Format: {ref: [lines]}
mutaLinesMap = {}
currentMutaRef = None
currentMutaLines = []
consumedIndices = set()
for i in range(len(lines)):
line = lines[i]
m = re.match('^\[(?P<ref>\d+)\]', line)
def completeMutaLines():
if currentMutaRef is not None and currentMutaLines:
mutaLinesMap[currentMutaRef] = currentMutaLines
for i, line in enumerate(lines):
m = mutantHeaderPattern.match(line)
# Start and reset at header line
if m:
ref = int(m.group('ref'))
# Attempt to apply mutation is useless w/o mutaplasmid, so skip it
# altogether if we have no info on it
try:
mutaName = lines[i + 1]
except IndexError:
continue
else:
consumedIndices.add(i)
consumedIndices.add(i + 1)
# Get custom attribute values
mutaAttrs = {}
try:
mutaAttrsLine = lines[i + 2]
except IndexError:
pass
else:
consumedIndices.add(i + 2)
pairs = [p.strip() for p in mutaAttrsLine.split(',')]
for pair in pairs:
try:
attrName, value = pair.split(' ')
except ValueError:
continue
try:
value = float(value)
except (ValueError, TypeError):
continue
attrInfo = getAttributeInfo(attrName.strip())
if attrInfo is None:
continue
mutaAttrs[attrInfo.ID] = value
mutaItem = _fetchItem(mutaName)
if mutaItem is None:
continue
data[ref] = (mutaItem, mutaAttrs)
# If we got here, we have seen at least correct reference line and
# mutaplasmid name line
i += 2
# Bonus points for seeing correct attrs line. Worst case we
# will have to scan it once again
if mutaAttrs:
i += 1
# Cleanup the lines from mutaplasmid info
completeMutaLines()
currentMutaRef = int(m.group('ref'))
currentMutaLines = []
currentMutaLines.append(m.group('tail'))
consumedIndices.add(i)
# Reset at blank line
elif not line:
completeMutaLines()
currentMutaRef = None
currentMutaLines = []
elif currentMutaRef is not None:
currentMutaLines.append(line)
consumedIndices.add(i)
else:
completeMutaLines()
# Clear mutant info from source
for i in sorted(consumedIndices, reverse=True):
del lines[i]
# Run parsing
data = {}
for ref, mutaLines in mutaLinesMap.items():
_, mutaType, mutaAttrs = parseMutant(mutaLines)
data[ref] = (mutaType, mutaAttrs)
return data
@@ -587,7 +566,7 @@ def _importCreateFit(lines):
shipType = m.group('shipType').strip()
fitName = m.group('fitName').strip()
try:
ship = _fetchItem(shipType)
ship = fetchItem(shipType)
try:
fit.ship = Ship(ship)
except ValueError:
@@ -599,20 +578,6 @@ def _importCreateFit(lines):
return fit
def _fetchItem(typeName, eagerCat=False):
sMkt = Market.getInstance()
eager = 'group.category' if eagerCat else None
try:
item = sMkt.getItem(typeName, eager=eager)
except:
pyfalog.warning('service.port.eft: unable to fetch item "{}"'.format(typeName))
return None
if sMkt.getPublicityByItem(item):
return item
else:
return None
def _clearTail(lst):
while lst and lst[-1] is None:
del lst[-1]
@@ -667,7 +632,7 @@ class Section:
class BaseItemSpec:
def __init__(self, typeName):
item = _fetchItem(typeName, eagerCat=True)
item = fetchItem(typeName, eagerCat=True)
if item is None:
raise EftImportError
self.typeName = typeName
@@ -704,7 +669,7 @@ class RegularItemSpec(BaseItemSpec):
def __fetchCharge(self, chargeName):
if chargeName:
charge = _fetchItem(chargeName, eagerCat=True)
charge = fetchItem(chargeName, eagerCat=True)
if not charge or charge.category.name != 'Charge':
charge = None
else:

79
service/port/muta.py Normal file
View File

@@ -0,0 +1,79 @@
# =============================================================================
# Copyright (C) 2014 Ryan Holmes
#
# This file is part of pyfa.
#
# pyfa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyfa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================
from eos.db.gamedata.queries import getAttributeInfo
from gui.utils.numberFormatter import roundToPrec
from service.port.shared import fetchItem
def renderMutant(mutant, firstPrefix='', prefix=''):
exportLines = []
mutatedAttrs = {}
for attrID, mutator in mutant.mutators.items():
attrName = getAttributeInfo(attrID).name
mutatedAttrs[attrName] = mutator.value
exportLines.append('{}{}'.format(firstPrefix, mutant.baseItem.name))
exportLines.append('{}{}'.format(prefix, mutant.mutaplasmid.item.name))
# Round to 7th significant number to avoid exporting float errors
customAttrsLine = ', '.join(
'{} {}'.format(a, roundToPrec(mutatedAttrs[a], 7))
for a in sorted(mutatedAttrs))
exportLines.append('{}{}'.format(prefix, customAttrsLine))
return '\n'.join(exportLines)
def parseMutant(lines):
# Fetch base item type
try:
baseName = lines[0]
except IndexError:
return None
baseType = fetchItem(baseName.strip())
if baseType is None:
return None, None, {}
# Fetch mutaplasmid item type and actual item
try:
mutaName = lines[1]
except IndexError:
return baseType, None, {}
mutaType = fetchItem(mutaName.strip())
if mutaType is None:
return baseType, None, {}
# Process mutated attribute values
try:
mutaAttrsLine = lines[2]
except IndexError:
return baseType, mutaType, {}
mutaAttrs = {}
pairs = [p.strip() for p in mutaAttrsLine.split(',')]
for pair in pairs:
try:
attrName, value = pair.split(' ')
except ValueError:
continue
try:
value = float(value)
except (ValueError, TypeError):
continue
attrInfo = getAttributeInfo(attrName.strip())
if attrInfo is None:
continue
mutaAttrs[attrInfo.ID] = value
return baseType, mutaType, mutaAttrs

View File

@@ -37,6 +37,7 @@ from service.port.esi import exportESI, importESI
from service.port.multibuy import exportMultiBuy
from service.port.shared import IPortUser, UserCancelException, processing_notify
from service.port.xml import importXml, exportXml
from service.port.muta import parseMutant
pyfalog = Logger(__name__)
@@ -188,18 +189,20 @@ class Port(object):
# TODO: catch the exception?
# activeFit is reserved?, bufferStr is unicode? (assume only clipboard string?
sFit = svcFit.getInstance()
_, fits = Port.importAuto(bufferStr, activeFit=activeFit)
for fit in fits:
fit.character = sFit.character
fit.damagePattern = sFit.pattern
fit.targetResists = sFit.targetResists
if len(fit.implants) > 0:
fit.implantLocation = ImplantLocation.FIT
else:
useCharImplants = sFit.serviceFittingOptions["useCharacterImplantsByDefault"]
fit.implantLocation = ImplantLocation.CHARACTER if useCharImplants else ImplantLocation.FIT
db.save(fit)
return fits
importType, importData = Port.importAuto(bufferStr, activeFit=activeFit)
if importType != "MutatedItem":
for fit in importData:
fit.character = sFit.character
fit.damagePattern = sFit.pattern
fit.targetResists = sFit.targetResists
if len(fit.implants) > 0:
fit.implantLocation = ImplantLocation.FIT
else:
useCharImplants = sFit.serviceFittingOptions["useCharacterImplantsByDefault"]
fit.implantLocation = ImplantLocation.CHARACTER if useCharImplants else ImplantLocation.FIT
db.save(fit)
return importType, importData
@classmethod
def importAuto(cls, string, path=None, activeFit=None, iportuser=None):
@@ -228,8 +231,16 @@ class Port(object):
if re.match("\[.*,.*\]", firstLine):
return "EFT", (cls.importEft(string),)
# Use DNA format for all other cases
return "DNA", (cls.importDna(string),)
# Check if string is in DNA format
if re.match("\d+(:\d+(;\d+))*::", firstLine):
return "DNA", (cls.importDna(string),)
# Assume that we import stand-alone abyssal module if all else fails
try:
return "MutatedItem", (parseMutant(string.split("\n")),)
except:
pass
# EFT-related methods
@staticmethod

View File

@@ -20,6 +20,13 @@
from abc import ABCMeta, abstractmethod
from logbook import Logger
from service.market import Market
pyfalog = Logger(__name__)
class UserCancelException(Exception):
"""when user cancel on port processing."""
@@ -68,3 +75,17 @@ class IPortUser(metaclass=ABCMeta):
def processing_notify(iportuser, flag, data):
if not iportuser.on_port_processing(flag, data):
raise UserCancelException
def fetchItem(typeName, eagerCat=False):
sMkt = Market.getInstance()
eager = 'group.category' if eagerCat else None
try:
item = sMkt.getItem(typeName, eager=eager)
except:
pyfalog.warning('service.port.shared: unable to fetch item "{}"'.format(typeName))
return None
if sMkt.getPublicityByItem(item):
return item
else:
return None