Merge branch 'master' into sso_v2
This commit is contained in:
8
service/conversions/releaseOct2021.py
Normal file
8
service/conversions/releaseOct2021.py
Normal file
@@ -0,0 +1,8 @@
|
||||
"""
|
||||
Conversion pack for October 2021 release
|
||||
"""
|
||||
|
||||
CONVERSIONS = {
|
||||
# Renamed items
|
||||
"Quafe Zero": "Quafe Zero Classic",
|
||||
}
|
||||
@@ -379,7 +379,7 @@ class Fit:
|
||||
return fits
|
||||
|
||||
def changeMutatedValuePrelim(self, mutator, value):
|
||||
pyfalog.debug("Changing mutated value for {} / {}: {} => {}".format(mutator.module, mutator.module.mutaplasmid, mutator.value, value))
|
||||
pyfalog.debug("Changing mutated value for {} / {}: {} => {}".format(mutator.item, mutator.item.mutaplasmid, mutator.value, value))
|
||||
if mutator.value != value:
|
||||
mutator.value = value
|
||||
eos.db.flush()
|
||||
|
||||
@@ -49,7 +49,25 @@ OFFLINE_SUFFIX = '/OFFLINE'
|
||||
NAME_CHARS = '[^,/\[\]]' # Characters which are allowed to be used in name
|
||||
|
||||
|
||||
class MutationExportData:
|
||||
|
||||
def __init__(self):
|
||||
self.reference = 1
|
||||
self.mutants = {}
|
||||
|
||||
def formatMutants(self):
|
||||
mutationLines = []
|
||||
if self.mutants:
|
||||
for mutantReference in sorted(self.mutants):
|
||||
mutant = self.mutants[mutantReference]
|
||||
mutationLines.append(renderMutant(mutant, firstPrefix='[{}] '.format(mutantReference), prefix=' '))
|
||||
return '\n'.join(mutationLines)
|
||||
|
||||
|
||||
def exportEft(fit, options, callback):
|
||||
|
||||
mutaData = MutationExportData()
|
||||
|
||||
# EFT formatted export is split in several sections, each section is
|
||||
# separated from another using 2 blank lines. Sections might have several
|
||||
# sub-sections, which are separated by 1 blank line
|
||||
@@ -58,46 +76,15 @@ def exportEft(fit, options, callback):
|
||||
header = '[{}, {}]'.format(fit.ship.item.typeName, fit.name)
|
||||
|
||||
# Section 1: modules, rigs, subsystems, services
|
||||
modsBySlotType = {}
|
||||
for module in fit.modules:
|
||||
modsBySlotType.setdefault(module.slot, []).append(module)
|
||||
modSection = []
|
||||
|
||||
mutants = {} # Format: {reference number: module}
|
||||
mutantReference = 1
|
||||
for slotType in SLOT_ORDER:
|
||||
rackLines = []
|
||||
modules = modsBySlotType.get(slotType, ())
|
||||
for module in modules:
|
||||
if module.item:
|
||||
# if module was mutated, use base item name for export
|
||||
if module.isMutated:
|
||||
modName = module.baseItem.typeName
|
||||
else:
|
||||
modName = module.item.typeName
|
||||
if module.isMutated and options[PortEftOptions.MUTATIONS]:
|
||||
mutants[mutantReference] = module
|
||||
mutationSuffix = ' [{}]'.format(mutantReference)
|
||||
mutantReference += 1
|
||||
else:
|
||||
mutationSuffix = ''
|
||||
modOfflineSuffix = ' {}'.format(OFFLINE_SUFFIX) if module.state == FittingModuleState.OFFLINE else ''
|
||||
if module.charge and options[PortEftOptions.LOADED_CHARGES]:
|
||||
rackLines.append('{}, {}{}{}'.format(
|
||||
modName, module.charge.typeName, modOfflineSuffix, mutationSuffix))
|
||||
else:
|
||||
rackLines.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix))
|
||||
else:
|
||||
rackLines.append('[Empty {} slot]'.format(
|
||||
FittingSlot(slotType).name.capitalize() if slotType is not None else ''))
|
||||
if rackLines:
|
||||
modSection.append('\n'.join(rackLines))
|
||||
if modSection:
|
||||
sections.append('\n\n'.join(modSection))
|
||||
moduleExport = exportModules(fit.modules, options, mutaData=mutaData)
|
||||
if moduleExport:
|
||||
sections.append(moduleExport)
|
||||
|
||||
# Section 2: drones, fighters
|
||||
minionSection = []
|
||||
droneExport = exportDrones(fit.drones)
|
||||
droneExport = exportDrones(
|
||||
fit.drones, exportMutants=options[PortEftOptions.MUTATIONS],
|
||||
mutaData=mutaData, standAlone=False)
|
||||
if droneExport:
|
||||
minionSection.append(droneExport)
|
||||
fighterExport = exportFighters(fit.fighters)
|
||||
@@ -125,14 +112,11 @@ def exportEft(fit, options, callback):
|
||||
if cargoExport:
|
||||
sections.append(cargoExport)
|
||||
|
||||
# Section 5: mutated modules' details
|
||||
mutationLines = []
|
||||
if mutants and options[PortEftOptions.MUTATIONS]:
|
||||
for mutantReference in sorted(mutants):
|
||||
mutant = mutants[mutantReference]
|
||||
mutationLines.append(renderMutant(mutant, firstPrefix='[{}] '.format(mutantReference), prefix=' '))
|
||||
if mutationLines:
|
||||
sections.append('\n'.join(mutationLines))
|
||||
# Section 5: mutated items' details
|
||||
if options[PortEftOptions.MUTATIONS]:
|
||||
mutationExport = mutaData.formatMutants()
|
||||
if mutationExport:
|
||||
sections.append(mutationExport)
|
||||
|
||||
text = '{}\n\n{}'.format(header, '\n\n\n'.join(sections))
|
||||
|
||||
@@ -142,11 +126,67 @@ def exportEft(fit, options, callback):
|
||||
return text
|
||||
|
||||
|
||||
def exportDrones(drones):
|
||||
def exportModules(modules, options, mutaData=None):
|
||||
if mutaData is None:
|
||||
mutaData = MutationExportData()
|
||||
modsBySlotType = {}
|
||||
for module in modules:
|
||||
modsBySlotType.setdefault(module.slot, []).append(module)
|
||||
modSection = []
|
||||
for slotType in SLOT_ORDER:
|
||||
rackLines = []
|
||||
rackModules = modsBySlotType.get(slotType, ())
|
||||
for module in rackModules:
|
||||
if module.item:
|
||||
# if module was mutated, use base item name for export
|
||||
if module.isMutated:
|
||||
modName = module.baseItem.typeName
|
||||
else:
|
||||
modName = module.item.typeName
|
||||
if module.isMutated and options[PortEftOptions.MUTATIONS]:
|
||||
mutaData.mutants[mutaData.reference] = module
|
||||
mutationSuffix = ' [{}]'.format(mutaData.reference)
|
||||
mutaData.reference += 1
|
||||
else:
|
||||
mutationSuffix = ''
|
||||
modOfflineSuffix = ' {}'.format(OFFLINE_SUFFIX) if module.state == FittingModuleState.OFFLINE else ''
|
||||
if module.charge and options[PortEftOptions.LOADED_CHARGES]:
|
||||
rackLines.append('{}, {}{}{}'.format(
|
||||
modName, module.charge.typeName, modOfflineSuffix, mutationSuffix))
|
||||
else:
|
||||
rackLines.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix))
|
||||
else:
|
||||
rackLines.append('[Empty {} slot]'.format(
|
||||
FittingSlot(slotType).name.capitalize() if slotType is not None else ''))
|
||||
if rackLines:
|
||||
modSection.append('\n'.join(rackLines))
|
||||
return '\n\n'.join(modSection)
|
||||
|
||||
|
||||
def exportDrones(drones, exportMutants=True, mutaData=None, standAlone=True):
|
||||
|
||||
def getDroneName(drone):
|
||||
if drone.isMutated:
|
||||
return drone.baseItem.typeName
|
||||
return drone.item.typeName
|
||||
|
||||
if mutaData is None:
|
||||
mutaData = MutationExportData()
|
||||
sections = []
|
||||
droneLines = []
|
||||
for drone in sorted(drones, key=lambda d: d.item.typeName):
|
||||
droneLines.append('{} x{}'.format(drone.item.typeName, drone.amount))
|
||||
return '\n'.join(droneLines)
|
||||
for drone in sorted(drones, key=getDroneName):
|
||||
if drone.isMutated and exportMutants:
|
||||
mutaData.mutants[mutaData.reference] = drone
|
||||
mutationSuffix = ' [{}]'.format(mutaData.reference)
|
||||
mutaData.reference += 1
|
||||
else:
|
||||
mutationSuffix = ''
|
||||
droneLines.append('{} x{}{}'.format(getDroneName(drone), drone.amount, mutationSuffix))
|
||||
if droneLines:
|
||||
sections.append('\n'.join(droneLines))
|
||||
if exportMutants and mutaData.mutants and standAlone:
|
||||
sections.append(mutaData.formatMutants())
|
||||
return '\n\n\n'.join(sections)
|
||||
|
||||
|
||||
def exportFighters(fighters):
|
||||
@@ -185,11 +225,11 @@ def importEft(lines):
|
||||
return
|
||||
|
||||
aFit = AbstractFit()
|
||||
aFit.mutations = _importGetMutationData(lines)
|
||||
aFit.mutations = importGetMutationData(lines)
|
||||
|
||||
stubPattern = '^\[.+?\]$'
|
||||
modulePattern = '^(?P<typeName>{0}+?)(,\s*(?P<chargeName>{0}+?))?(?P<offline>\s*{1})?(\s*\[(?P<mutation>\d+?)\])?$'.format(NAME_CHARS, OFFLINE_SUFFIX)
|
||||
droneCargoPattern = '^(?P<typeName>{}+?) x(?P<amount>\d+?)$'.format(NAME_CHARS)
|
||||
droneCargoPattern = '^(?P<typeName>{}+?) x(?P<amount>\d+?)(\s*\[(?P<mutation>\d+?)\])?$'.format(NAME_CHARS)
|
||||
|
||||
sections = []
|
||||
for section in _importSectionIter(lines):
|
||||
@@ -209,6 +249,8 @@ def importEft(lines):
|
||||
else:
|
||||
itemSpec.amount = int(m.group('amount'))
|
||||
section.itemSpecs.append(itemSpec)
|
||||
if m.group('mutation'):
|
||||
itemSpec.mutationIdx = int(m.group('mutation'))
|
||||
continue
|
||||
# All other items
|
||||
m = re.match(modulePattern, line)
|
||||
@@ -297,7 +339,7 @@ def importEft(lines):
|
||||
fit.implants.append(implant)
|
||||
for booster in aFit.boosters:
|
||||
fit.boosters.append(booster)
|
||||
for drone in aFit.drones.values():
|
||||
for drone in aFit.drones:
|
||||
fit.drones.append(drone)
|
||||
for fighter in aFit.fighters:
|
||||
fit.fighters.append(fighter)
|
||||
@@ -530,8 +572,7 @@ def _importPrepare(lines):
|
||||
mutantHeaderPattern = re.compile('^\[(?P<ref>\d+)\](?P<tail>.*)')
|
||||
|
||||
|
||||
def _importGetMutationData(lines):
|
||||
data = {}
|
||||
def importGetMutationData(lines):
|
||||
# Format: {ref: [lines]}
|
||||
mutaLinesMap = {}
|
||||
currentMutaRef = None
|
||||
@@ -725,6 +766,7 @@ class MultiItemSpec(BaseItemSpec):
|
||||
def __init__(self, typeName):
|
||||
super().__init__(typeName)
|
||||
self.amount = 0
|
||||
self.mutationIdx = None
|
||||
|
||||
@property
|
||||
def isDrone(self):
|
||||
@@ -752,7 +794,7 @@ class AbstractFit:
|
||||
# Non-modules
|
||||
self.implants = []
|
||||
self.boosters = []
|
||||
self.drones = {} # Format: {item: Drone}
|
||||
self.drones = []
|
||||
self.fighters = []
|
||||
self.cargo = {} # Format: {item: Cargo}
|
||||
# Other stuff
|
||||
@@ -856,9 +898,34 @@ class AbstractFit:
|
||||
def addDrone(self, itemSpec):
|
||||
if itemSpec is None:
|
||||
return
|
||||
if itemSpec.item not in self.drones:
|
||||
self.drones[itemSpec.item] = Drone(itemSpec.item)
|
||||
self.drones[itemSpec.item].amount += itemSpec.amount
|
||||
drone = None
|
||||
if itemSpec.mutationIdx in self.mutations:
|
||||
mutaItem, mutaAttrs = self.mutations[itemSpec.mutationIdx]
|
||||
mutaplasmid = getDynamicItem(mutaItem.ID)
|
||||
if mutaplasmid:
|
||||
try:
|
||||
drone = Drone(mutaplasmid.resultingItem, itemSpec.item, mutaplasmid)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
for attrID, mutator in drone.mutators.items():
|
||||
if attrID in mutaAttrs:
|
||||
mutator.value = mutaAttrs[attrID]
|
||||
if drone is None:
|
||||
try:
|
||||
drone = Drone(itemSpec.item)
|
||||
except ValueError:
|
||||
return
|
||||
drone.amount = itemSpec.amount
|
||||
if drone.isMutated:
|
||||
self.drones.append(drone)
|
||||
else:
|
||||
for fitDrone in self.drones:
|
||||
if fitDrone.item.ID == itemSpec.item.ID:
|
||||
fitDrone.amount += drone.amount
|
||||
break
|
||||
else:
|
||||
self.drones.append(drone)
|
||||
|
||||
def addFighter(self, itemSpec):
|
||||
if itemSpec is None:
|
||||
@@ -875,7 +942,7 @@ class AbstractFit:
|
||||
self.cargo[itemSpec.item].amount += itemSpec.amount
|
||||
|
||||
|
||||
def _lineIter(text):
|
||||
def lineIter(text):
|
||||
"""Iterate over non-blank lines."""
|
||||
for line in text.splitlines():
|
||||
line = line.strip()
|
||||
@@ -883,11 +950,11 @@ def _lineIter(text):
|
||||
yield line
|
||||
|
||||
|
||||
def parseAdditions(text):
|
||||
def parseAdditions(text, mutaData=None):
|
||||
items = []
|
||||
sMkt = Market.getInstance()
|
||||
pattern = '^(?P<typeName>{}+?)( x(?P<amount>\d+?))?$'.format(NAME_CHARS)
|
||||
for line in _lineIter(text):
|
||||
pattern = '^(?P<typeName>{}+?)( x(?P<amount>\d+?))?(\s*\[(?P<mutaref>\d+?)\])?$'.format(NAME_CHARS)
|
||||
for line in lineIter(text):
|
||||
m = re.match(pattern, line)
|
||||
if not m:
|
||||
continue
|
||||
@@ -896,19 +963,27 @@ def parseAdditions(text):
|
||||
continue
|
||||
amount = m.group('amount')
|
||||
amount = 1 if amount is None else int(amount)
|
||||
items.append((item, amount))
|
||||
mutaRef = int(m.group('mutaref')) if m.group('mutaref') else None
|
||||
if mutaRef and mutaData and mutaRef in mutaData:
|
||||
mutation = mutaData[mutaRef]
|
||||
else:
|
||||
mutation = None
|
||||
items.append((item, amount, mutation))
|
||||
return items
|
||||
|
||||
|
||||
def isValidDroneImport(text):
|
||||
pattern = 'x\d+$'
|
||||
for line in _lineIter(text):
|
||||
lines = list(lineIter(text))
|
||||
mutaData = importGetMutationData(lines)
|
||||
text = '\n'.join(lines)
|
||||
pattern = 'x\d+(\s*\[\d+\])?$'
|
||||
for line in lineIter(text):
|
||||
if not re.search(pattern, line):
|
||||
return False, ()
|
||||
itemData = parseAdditions(text)
|
||||
itemData = parseAdditions(text, mutaData=mutaData)
|
||||
if not itemData:
|
||||
return False, ()
|
||||
for item, amount in itemData:
|
||||
for item, amount, mutation in itemData:
|
||||
if not item.isDrone:
|
||||
return False, ()
|
||||
return True, itemData
|
||||
@@ -916,13 +991,13 @@ def isValidDroneImport(text):
|
||||
|
||||
def isValidFighterImport(text):
|
||||
pattern = 'x\d+$'
|
||||
for line in _lineIter(text):
|
||||
for line in lineIter(text):
|
||||
if not re.search(pattern, line):
|
||||
return False, ()
|
||||
itemData = parseAdditions(text)
|
||||
if not itemData:
|
||||
return False, ()
|
||||
for item, amount in itemData:
|
||||
for item, amount, mutation in itemData:
|
||||
if not item.isFighter:
|
||||
return False, ()
|
||||
return True, itemData
|
||||
@@ -930,13 +1005,13 @@ def isValidFighterImport(text):
|
||||
|
||||
def isValidCargoImport(text):
|
||||
pattern = 'x\d+$'
|
||||
for line in _lineIter(text):
|
||||
for line in lineIter(text):
|
||||
if not re.search(pattern, line):
|
||||
return False, ()
|
||||
itemData = parseAdditions(text)
|
||||
if not itemData:
|
||||
return False, ()
|
||||
for item, amount in itemData:
|
||||
for item, amount, mutation in itemData:
|
||||
if item.isAbyssal:
|
||||
return False, ()
|
||||
return True, itemData
|
||||
@@ -944,13 +1019,13 @@ def isValidCargoImport(text):
|
||||
|
||||
def isValidImplantImport(text):
|
||||
pattern = 'x\d+$'
|
||||
for line in _lineIter(text):
|
||||
for line in lineIter(text):
|
||||
if re.search(pattern, line):
|
||||
return False, ()
|
||||
itemData = parseAdditions(text)
|
||||
if not itemData:
|
||||
return False, ()
|
||||
for item, amount in itemData:
|
||||
for item, amount, mutation in itemData:
|
||||
if not item.isImplant:
|
||||
return False, ()
|
||||
return True, itemData
|
||||
@@ -958,13 +1033,13 @@ def isValidImplantImport(text):
|
||||
|
||||
def isValidBoosterImport(text):
|
||||
pattern = 'x\d+$'
|
||||
for line in _lineIter(text):
|
||||
for line in lineIter(text):
|
||||
if re.search(pattern, line):
|
||||
return False, ()
|
||||
itemData = parseAdditions(text)
|
||||
if not itemData:
|
||||
return False, ()
|
||||
for item, amount in itemData:
|
||||
for item, amount, mutation in itemData:
|
||||
if not item.isBooster:
|
||||
return False, ()
|
||||
return True, itemData
|
||||
|
||||
@@ -232,14 +232,14 @@ class Port:
|
||||
|
||||
# If we've got source file name which is used to describe ship name
|
||||
# and first line contains something like [setup name], detect as eft config file
|
||||
if re.match("\[.*\]", firstLine) and path is not None:
|
||||
if re.match("^\s*\[.*\]", firstLine) and path is not None:
|
||||
filename = os.path.split(path)[1]
|
||||
shipName = filename.rsplit('.')[0]
|
||||
return "EFT Config", True, cls.importEftCfg(shipName, lines, iportuser)
|
||||
|
||||
# If no file is specified and there's comma between brackets,
|
||||
# consider that we have [ship, setup name] and detect like eft export format
|
||||
if re.match("\[.*,.*\]", firstLine):
|
||||
if re.match("^\s*\[.*,.*\]", firstLine):
|
||||
return "EFT", True, (cls.importEft(lines),)
|
||||
|
||||
# Check if string is in DNA format
|
||||
|
||||
Reference in New Issue
Block a user