diff --git a/service/eftPort.py b/service/eftPort.py
new file mode 100644
index 000000000..de69bd966
--- /dev/null
+++ b/service/eftPort.py
@@ -0,0 +1,526 @@
+# =============================================================================
+# 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 .
+# =============================================================================
+
+
+import re
+
+from logbook import Logger
+
+from eos.db.gamedata.queries import getAttributeInfo
+from eos.saveddata.citadel import Citadel
+from eos.saveddata.module import Module, Slot, State
+from eos.saveddata.ship import Ship
+from gui.utils.numberFormatter import roundToPrec
+from service.fit import Fit as svcFit
+from service.market import Market
+
+
+pyfalog = Logger(__name__)
+
+
+def fetchItem(typeName, eagerCat=True):
+ sMkt = Market.getInstance()
+ eager = 'group.category' if eagerCat else None
+ try:
+ return sMkt.getItem(typeName, eager=eager)
+ except:
+ pyfalog.warning('EftPort: unable to fetch item "{}"'.format(typeName))
+ return
+
+
+class EftImportError(Exception):
+ """Exception class emitted and consumed by EFT importer/exporter internally."""
+ ...
+
+
+class AmountMap(dict):
+
+ def add(self, entity, amount):
+ if entity not in self:
+ self[entity] = 0
+ self[entity] += amount
+
+
+class AbstractFit:
+
+ def __init__(self):
+ self.modulesHigh = []
+ self.modulesMed = []
+ self.modulesLow = []
+ self.rigs = []
+ self.subsystems = []
+ self.services = []
+ self.drones = AmountMap()
+ self.fighters = AmountMap()
+ self.implants = set()
+ self.boosters = set()
+ self.cargo = AmountMap()
+
+ # def addModule(self, m):
+ # modContMap = {
+ # Slot.HIGH: self.modulesHigh,
+ # Slot.MED: self.modulesMed,
+ # Slot.LOW: self.modulesLow,
+ # Slot.RIG: self.rigs,
+ # Slot.SUBSYSTEM: self.subsystems,
+ # Slot.SERVICE: self.services}
+
+
+class Section:
+
+ def __init__(self):
+ self.lines = []
+ self.itemData = []
+ self.__itemDataCats = None
+
+ @property
+ def itemDataCats(self):
+ if self.__itemDataCats is None:
+ cats = set()
+ for itemSpec in self.itemData:
+ if itemSpec is None:
+ continue
+ cats.add(itemSpec.item.category.name)
+ self.__itemDataCats = tuple(sorted(cats))
+ return self.__itemDataCats
+
+ def cleanItemDataTail(self):
+ while self.itemData and self.itemData[-1] is None:
+ del self.itemData[-1]
+
+
+class BaseItemSpec:
+
+ def __init__(self, typeName):
+ item = fetchItem(typeName, eagerCat=True)
+ if item is None:
+ raise EftImportError
+ self.typeName = typeName
+ self.item = item
+
+
+class ItemSpec(BaseItemSpec):
+
+ def __init__(self, typeName, chargeName=None):
+ super().__init__(typeName)
+ self.charge = self.__fetchCharge(chargeName)
+ self.offline = False
+ self.mutationIdx = None
+
+ def __fetchCharge(self, chargeName):
+ if chargeName:
+ charge = fetchItem(chargeName, eagerCat=True)
+ if charge.category.name != 'Charge':
+ charge = None
+ else:
+ charge = None
+ return charge
+
+
+class MultiItemSpec(BaseItemSpec):
+
+ def __init__(self, typeName):
+ super().__init__(typeName)
+ self.amount = 0
+
+
+class EftPort:
+
+ SLOT_ORDER = [Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERVICE]
+ OFFLINE_SUFFIX = ' /OFFLINE'
+
+ @classmethod
+ def exportEft(cls, fit, mutations, implants):
+ # 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
+ sections = []
+
+ header = '[{}, {}]'.format(fit.ship.item.name, fit.name)
+
+ # Section 1: modules, rigs, subsystems, services
+ modsBySlotType = {}
+ sFit = svcFit.getInstance()
+ for module in fit.modules:
+ modsBySlotType.setdefault(module.slot, []).append(module)
+ modSection = []
+
+ mutants = {} # Format: {reference number: module}
+ mutantReference = 1
+ for slotType in cls.SLOT_ORDER:
+ rackLines = []
+ modules = modsBySlotType.get(slotType, ())
+ for module in modules:
+ if module.item:
+ mutated = bool(module.mutators)
+ # if module was mutated, use base item name for export
+ if mutated:
+ modName = module.baseItem.name
+ else:
+ modName = module.item.name
+ if mutated and mutations:
+ mutants[mutantReference] = module
+ mutationSuffix = ' [{}]'.format(mutantReference)
+ mutantReference += 1
+ else:
+ mutationSuffix = ''
+ modOfflineSuffix = cls.OFFLINE_SUFFIX if module.state == State.OFFLINE else ''
+ if module.charge and sFit.serviceFittingOptions['exportCharges']:
+ rackLines.append('{}, {}{}{}'.format(
+ modName, module.charge.name, modOfflineSuffix, mutationSuffix))
+ else:
+ rackLines.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix))
+ else:
+ rackLines.append('[Empty {} slot]'.format(
+ Slot.getName(slotType).capitalize() if slotType is not None else ''))
+ if rackLines:
+ modSection.append('\n'.join(rackLines))
+ if modSection:
+ sections.append('\n\n'.join(modSection))
+
+ # Section 2: drones, fighters
+ minionSection = []
+ droneLines = []
+ for drone in sorted(fit.drones, key=lambda d: d.item.name):
+ droneLines.append('{} x{}'.format(drone.item.name, drone.amount))
+ if droneLines:
+ minionSection.append('\n'.join(droneLines))
+ fighterLines = []
+ for fighter in sorted(fit.fighters, key=lambda f: f.item.name):
+ fighterLines.append('{} x{}'.format(fighter.item.name, fighter.amountActive))
+ if fighterLines:
+ minionSection.append('\n'.join(fighterLines))
+ if minionSection:
+ sections.append('\n\n'.join(minionSection))
+
+ # Section 3: implants, boosters
+ if implants:
+ charSection = []
+ implantLines = []
+ for implant in fit.implants:
+ implantLines.append(implant.item.name)
+ if implantLines:
+ charSection.append('\n'.join(implantLines))
+ boosterLines = []
+ for booster in fit.boosters:
+ boosterLines.append(booster.item.name)
+ if boosterLines:
+ charSection.append('\n'.join(boosterLines))
+ if charSection:
+ sections.append('\n\n'.join(charSection))
+
+ # Section 4: cargo
+ cargoLines = []
+ for cargo in sorted(
+ fit.cargo,
+ key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name)
+ ):
+ cargoLines.append('{} x{}'.format(cargo.item.name, cargo.amount))
+ if cargoLines:
+ sections.append('\n'.join(cargoLines))
+
+ # Section 5: mutated modules' details
+ mutationLines = []
+ if mutants and mutations:
+ 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))
+ if mutationLines:
+ sections.append('\n'.join(mutationLines))
+
+ return '{}\n\n{}'.format(header, '\n\n\n'.join(sections))
+
+ @classmethod
+ def importEft(cls, eftString):
+ lines = cls.__prepareImportString(eftString)
+ try:
+ fit = cls.__createFit(lines)
+ except EftImportError:
+ return
+
+ aFit = AbstractFit()
+
+ stubPattern = '^\[.+\]$'
+ modulePattern = '^(?P[^,/]+)(, (?P[^,/]+))?(?P{})?( \[(?P\d+)\])?$'.format(cls.OFFLINE_SUFFIX)
+ droneCargoPattern = '^(?P[^,/]+) x(?P\d+)$'
+
+ dronebaySeen = False
+ fightersSeen = False
+ for section in cls.__importSectionIter(lines):
+ for line in section.lines:
+ # Stub line
+ if re.match(stubPattern, line):
+ section.itemData.append(None)
+ continue
+ # Items with quantity specifier
+ m = re.match(droneCargoPattern, line)
+ if m:
+ try:
+ itemSpec = MultiItemSpec(m.group('typeName'))
+ # Items which cannot be fetched are considered as stubs
+ except EftImportError:
+ section.itemData.append(None)
+ else:
+ itemSpec.amount = int(m.group('amount'))
+ section.itemData.append(itemSpec)
+ # All other items
+ m = re.match(modulePattern, line)
+ if m:
+ try:
+ itemSpec = ItemSpec(m.group('typeName'), chargeName=m.group('chargeName'))
+ # Items which cannot be fetched are considered as stubs
+ except EftImportError:
+ section.itemData.append(None)
+ else:
+ if m.group('offline'):
+ itemSpec.offline = True
+ if m.group('mutation'):
+ itemSpec.mutationIdx = int(m.group('mutation'))
+ section.itemData.append(itemSpec)
+ section.cleanItemDataTail()
+ # Finally, start putting items into intermediate containers
+ # All items in section have quantity specifier
+ if all(isinstance(id, MultiItemSpec) for id in section.itemData):
+ # Dronebay
+ if len(section.itemDataCats) == 1 and section.itemDataCats[0] == 'Drone' and not dronebaySeen:
+ for entry in section.itemData:
+ aFit.drones.add(entry['typeName'], entry['amount'])
+ dronebaySeen = True
+ # Fighters
+ elif len(section.itemDataCats) == 1 and section.itemDataCats[0] == 'Fighter' and not fightersSeen:
+ for entry in section.itemData:
+ aFit.fighters.add(entry['typeName'], entry['amount'])
+ fightersSeen = True
+ # Cargo
+ else:
+ for entry in section.itemData:
+ aFit.cargo.add(entry['typeName'], entry['amount'])
+ # All of items are normal or stubs
+ elif all(isinstance(id, ItemSpec) or id is None for id in section.itemData):
+ if len(section.itemDataCats) == 1:
+ if section.itemDataCats[0] in ('Module', 'Subsystem', 'Structure Module'):
+ slotTypes = set()
+ for entry in itemData:
+ if entry['type'] == 'stub':
+ continue
+ try:
+ m = Module(entry['item'])
+ except ValueError:
+ m = None
+ else:
+ slotTypes.add(m.slot)
+ entry['module'] = m
+ # If whole section uses container of the same type,
+ if len(slotTypes) == 1:
+ pass
+ else:
+ pass
+
+ else:
+ pass
+ else:
+ pass
+
+ # Mix between all types
+ else:
+ pass
+
+
+
+ # maintain map of drones and their quantities
+ droneMap = {}
+ cargoMap = {}
+ moduleList = []
+ for i in range(1, len(lines)):
+ ammoName = None
+ extraAmount = None
+
+ line = lines[i].strip()
+ if not line:
+ continue
+
+ setOffline = line.endswith(offineSuffix)
+ if setOffline is True:
+ # remove offline suffix from line
+ line = line[:len(line) - len(offineSuffix)]
+
+ modAmmo = line.split(",")
+ # matches drone and cargo with x{qty}
+ modExtra = modAmmo[0].split(" x")
+
+ if len(modAmmo) == 2:
+ # line with a module and ammo
+ ammoName = modAmmo[1].strip()
+ modName = modAmmo[0].strip()
+ elif len(modExtra) == 2:
+ # line with drone/cargo and qty
+ extraAmount = modExtra[1].strip()
+ modName = modExtra[0].strip()
+ else:
+ # line with just module
+ modName = modExtra[0].strip()
+
+ try:
+ # get item information. If we are on a Drone/Cargo line, throw out cargo
+ item = sMkt.getItem(modName, eager="group.category")
+ except:
+ # if no data can be found (old names)
+ pyfalog.warning("no data can be found (old names)")
+ continue
+
+ if not item.published:
+ continue
+
+ if item.category.name == "Drone":
+ extraAmount = int(extraAmount) if extraAmount is not None else 1
+ if modName not in droneMap:
+ droneMap[modName] = 0
+ droneMap[modName] += extraAmount
+ elif item.category.name == "Fighter":
+ extraAmount = int(extraAmount) if extraAmount is not None else 1
+ fighterItem = Fighter(item)
+ if extraAmount > fighterItem.fighterSquadronMaxSize: # Amount bigger then max fightergroup size
+ extraAmount = fighterItem.fighterSquadronMaxSize
+ if fighterItem.fits(fit):
+ fit.fighters.append(fighterItem)
+
+ if len(modExtra) == 2 and item.category.name != "Drone" and item.category.name != "Fighter":
+ extraAmount = int(extraAmount) if extraAmount is not None else 1
+ if modName not in cargoMap:
+ cargoMap[modName] = 0
+ cargoMap[modName] += extraAmount
+ elif item.category.name == "Implant":
+ if "implantness" in item.attributes:
+ fit.implants.append(Implant(item))
+ elif "boosterness" in item.attributes:
+ fit.boosters.append(Booster(item))
+ else:
+ pyfalog.error("Failed to import implant: {0}", line)
+ # elif item.category.name == "Subsystem":
+ # try:
+ # subsystem = Module(item)
+ # except ValueError:
+ # continue
+ #
+ # if subsystem.fits(fit):
+ # fit.modules.append(subsystem)
+ else:
+ try:
+ m = Module(item)
+ except ValueError:
+ continue
+ # Add subsystems before modules to make sure T3 cruisers have subsystems installed
+ if item.category.name == "Subsystem":
+ if m.fits(fit):
+ fit.modules.append(m)
+ else:
+ if ammoName:
+ try:
+ ammo = sMkt.getItem(ammoName)
+ if m.isValidCharge(ammo) and m.charge is None:
+ m.charge = ammo
+ except:
+ pass
+
+ if setOffline is True and m.isValidState(State.OFFLINE):
+ m.state = State.OFFLINE
+ elif m.isValidState(State.ACTIVE):
+ m.state = State.ACTIVE
+
+ moduleList.append(m)
+
+ # Recalc to get slot numbers correct for T3 cruisers
+ svcFit.getInstance().recalc(fit)
+
+ for m in moduleList:
+ if m.fits(fit):
+ m.owner = fit
+ if not m.isValidState(m.state):
+ pyfalog.warning("Error: Module {0} cannot have state {1}", m, m.state)
+
+ fit.modules.append(m)
+
+ for droneName in droneMap:
+ d = Drone(sMkt.getItem(droneName))
+ d.amount = droneMap[droneName]
+ fit.drones.append(d)
+
+ for cargoName in cargoMap:
+ c = Cargo(sMkt.getItem(cargoName))
+ c.amount = cargoMap[cargoName]
+ fit.cargo.append(c)
+
+ return fit
+
+ @staticmethod
+ def __prepareImportString(eftString):
+ lines = eftString.splitlines()
+ for i in range(len(lines)):
+ lines[i] = lines[i].strip()
+ while lines and not lines[0]:
+ del lines[0]
+ while lines and not lines[-1]:
+ del lines[-1]
+ return lines
+
+ @classmethod
+ def __createFit(cls, lines):
+ """Create fit and set top-level entity (ship or citadel)."""
+ fit = Fit()
+ header = lines.pop(0)
+ m = re.match('\[(?P[\w\s]+), (?P.+)\]', header)
+ if not m:
+ pyfalog.warning('EftPort.importEft: corrupted fit header')
+ raise EftImportError
+ shipType = m.group('shipType').strip()
+ fitName = m.group('fitName').strip()
+ try:
+ ship = fetchItem(shipType, eagerCat=False)
+ try:
+ fit.ship = Ship(ship)
+ except ValueError:
+ fit.ship = Citadel(ship)
+ fit.name = fitName
+ except:
+ pyfalog.warning('EftPort.importEft: exception caught when parsing header')
+ raise EftImportError
+ return fit
+
+ @staticmethod
+ def __importSectionIter(lines):
+ section = Section()
+ for line in lines:
+ if not line:
+ if section.lines:
+ yield section
+ section = Section()
+ else:
+ section.lines.append(line)
+ if section.lines:
+ yield section
diff --git a/service/port.py b/service/port.py
index f67c6e4ff..bf1ff4f90 100644
--- a/service/port.py
+++ b/service/port.py
@@ -32,8 +32,6 @@ from codecs import open
import xml.parsers.expat
from eos import db
-from eos.db.gamedata.queries import getAttributeInfo
-from gui.utils.numberFormatter import roundToPrec
from service.fit import Fit as svcFit
# noinspection PyPackageRequirements
@@ -53,6 +51,7 @@ from utils.strfunctions import sequential_rep, replace_ltgt
from abc import ABCMeta, abstractmethod
from service.esi import Esi
+from service.eftPort import EftPort
from collections import OrderedDict
@@ -62,7 +61,6 @@ class ESIExportException(Exception):
pyfalog = Logger(__name__)
-EFT_SLOT_ORDER = [Slot.LOW, Slot.MED, Slot.HIGH, Slot.RIG, Slot.SUBSYSTEM, Slot.SERVICE]
INV_FLAGS = {
Slot.LOW: 11,
Slot.MED: 19,
@@ -213,11 +211,7 @@ class IPortUser(metaclass=ABCMeta):
class Port(object):
- """
- 2017/03/31 NOTE: About change
- 1. want to keep the description recorded in fit
- 2. i think should not write wx.CallAfter in here
- """
+ """Service which houses all import/export format functions"""
instance = None
__tag_replace_flag = True
@@ -351,8 +345,6 @@ class Port(object):
db.save(fit)
return fits
- """Service which houses all import/export format functions"""
-
@classmethod
def exportESI(cls, ofit, callback=None):
# A few notes:
@@ -625,248 +617,7 @@ class Port(object):
@staticmethod
def importEft(eftString):
- # Split passed string in lines and clean them up
- lines = eftString.splitlines()
- for i in range(len(lines)):
- lines[i] = lines[i].strip()
- while lines and not lines[0]:
- del lines[0]
- while lines and not lines[-1]:
- del lines[-1]
-
- sMkt = Market.getInstance()
- offineSuffix = ' /OFFLINE'
-
- fit = Fit()
-
- # Ship and fit name from header
- header = lines.pop(0)
- m = re.match('\[(?P[\w\s]+), (?P.+)\]', header)
- if not m:
- pyfalog.warning('Corrupted fit header in importEft')
- return
- shipType = m.group('shipType').strip()
- fitName = m.group('fitName').strip()
- try:
- ship = sMkt.getItem(shipType)
- try:
- fit.ship = Ship(ship)
- except ValueError:
- fit.ship = Citadel(ship)
- fit.name = fitName
- except:
- pyfalog.warning("Exception caught in importEft")
- return
-
- def sectionIter(lines):
- section = []
- for line in lines:
- if not line:
- if section:
- yield section
- section = []
- section.append(line)
- if section:
- yield section
-
- stubPattern = '^\[.+\]$'
- modulePattern = '^(?P[^,/]+)(, (?P[^,/]+))?(?P /OFFLINE)?( \[(?P\d+)\])?$'
- droneCargoPattern = '^(?P[^,/]+) x(?P\d+)$'
-
- sections = []
- for section in sectionIter(lines):
- sectionItemData = []
- for line in section:
- # Stub line
- if re.match(stubPattern, line):
- sectionItemData.append({'type': 'stub'})
- continue
- # Items with quantity specifier
- m = re.match(droneCargoPattern, line)
- if m:
- sectionItemData.append({
- 'type': 'multi',
- 'typeName': m.group('typeName'),
- 'amount': int(m.group('amount'))})
- continue
- # All other items
- m = re.match(modulePattern, line)
- if m:
- sectionItemData.append({
- 'type': 'normal',
- 'typeName': m.group('typeName'),
- 'chargeName': m.group('charge'),
- 'offline': True if m.group('offline') else False,
- 'mutation': int(m.group('mutation')) if m.group('mutation') else None})
- # Strip stubs from tail
- while sectionItemData and sectionItemData[-1]['type'] == 'stub':
- del sectionItemData[-1]
- if sectionItemData:
- sections.append(sectionItemData)
-
-
-
- for sectionItemData in sections:
- sectionCats = set()
- for entry in sectionItemData:
- if entry['type'] == 'stub':
- continue
- try:
- item = sMkt.getItem(entry['typeName'], eager='group.category')
- except:
- pyfalog.warning('no data can be found (old names)')
- entry['type'] = 'stub'
- continue
- entry['item'] = item
- import sys
- sys.stderr.write('{}\n'.format(item.slot))
- sectionCats.add(item.category.name)
- processStubs = (
- # To process stubs, we must make sure that all the items in section
- # are from the same category
- len(sectionCats) == 1 and tuple(sectionCats)[0] == 'Module' and
- # And that they do not contain items with quantity specifier
- all(i['type'] in ('stub', 'normal') for i in sectionItemData))
- isDronebay = (
- len(sectionCats) == 1 and tuple(sectionCats)[0] == 'Drone' and
- all(i['type'] == 'multi' for i in sectionItemData))
- isFighterbay = (
- len(sectionCats) == 1 and tuple(sectionCats)[0] == 'Fighter' and
- all(i['type'] == 'multi' for i in sectionItemData))
-
-
-
-
-
-
-
-
-
-
- # maintain map of drones and their quantities
- droneMap = {}
- cargoMap = {}
- moduleList = []
- for i in range(1, len(lines)):
- ammoName = None
- extraAmount = None
-
- line = lines[i].strip()
- if not line:
- continue
-
- setOffline = line.endswith(offineSuffix)
- if setOffline is True:
- # remove offline suffix from line
- line = line[:len(line) - len(offineSuffix)]
-
- modAmmo = line.split(",")
- # matches drone and cargo with x{qty}
- modExtra = modAmmo[0].split(" x")
-
- if len(modAmmo) == 2:
- # line with a module and ammo
- ammoName = modAmmo[1].strip()
- modName = modAmmo[0].strip()
- elif len(modExtra) == 2:
- # line with drone/cargo and qty
- extraAmount = modExtra[1].strip()
- modName = modExtra[0].strip()
- else:
- # line with just module
- modName = modExtra[0].strip()
-
- try:
- # get item information. If we are on a Drone/Cargo line, throw out cargo
- item = sMkt.getItem(modName, eager="group.category")
- except:
- # if no data can be found (old names)
- pyfalog.warning("no data can be found (old names)")
- continue
-
- if not item.published:
- continue
-
- if item.category.name == "Drone":
- extraAmount = int(extraAmount) if extraAmount is not None else 1
- if modName not in droneMap:
- droneMap[modName] = 0
- droneMap[modName] += extraAmount
- elif item.category.name == "Fighter":
- extraAmount = int(extraAmount) if extraAmount is not None else 1
- fighterItem = Fighter(item)
- if extraAmount > fighterItem.fighterSquadronMaxSize: # Amount bigger then max fightergroup size
- extraAmount = fighterItem.fighterSquadronMaxSize
- if fighterItem.fits(fit):
- fit.fighters.append(fighterItem)
-
- if len(modExtra) == 2 and item.category.name != "Drone" and item.category.name != "Fighter":
- extraAmount = int(extraAmount) if extraAmount is not None else 1
- if modName not in cargoMap:
- cargoMap[modName] = 0
- cargoMap[modName] += extraAmount
- elif item.category.name == "Implant":
- if "implantness" in item.attributes:
- fit.implants.append(Implant(item))
- elif "boosterness" in item.attributes:
- fit.boosters.append(Booster(item))
- else:
- pyfalog.error("Failed to import implant: {0}", line)
- # elif item.category.name == "Subsystem":
- # try:
- # subsystem = Module(item)
- # except ValueError:
- # continue
- #
- # if subsystem.fits(fit):
- # fit.modules.append(subsystem)
- else:
- try:
- m = Module(item)
- except ValueError:
- continue
- # Add subsystems before modules to make sure T3 cruisers have subsystems installed
- if item.category.name == "Subsystem":
- if m.fits(fit):
- fit.modules.append(m)
- else:
- if ammoName:
- try:
- ammo = sMkt.getItem(ammoName)
- if m.isValidCharge(ammo) and m.charge is None:
- m.charge = ammo
- except:
- pass
-
- if setOffline is True and m.isValidState(State.OFFLINE):
- m.state = State.OFFLINE
- elif m.isValidState(State.ACTIVE):
- m.state = State.ACTIVE
-
- moduleList.append(m)
-
- # Recalc to get slot numbers correct for T3 cruisers
- svcFit.getInstance().recalc(fit)
-
- for m in moduleList:
- if m.fits(fit):
- m.owner = fit
- if not m.isValidState(m.state):
- pyfalog.warning("Error: Module {0} cannot have state {1}", m, m.state)
-
- fit.modules.append(m)
-
- for droneName in droneMap:
- d = Drone(sMkt.getItem(droneName))
- d.amount = droneMap[droneName]
- fit.drones.append(d)
-
- for cargoName in cargoMap:
- c = Cargo(sMkt.getItem(cargoName))
- c.amount = cargoMap[cargoName]
- fit.cargo.append(c)
-
- return fit
+ return EftPort.importEft(eftString)
@staticmethod
def importEftCfg(shipname, contents, iportuser=None):
@@ -1159,119 +910,12 @@ class Port(object):
@classmethod
- def exportEft(cls, fit, mutations=True, implants=False):
- # 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
- sections = []
-
- header = '[{}, {}]'.format(fit.ship.item.name, fit.name)
-
- # Section 1: modules, rigs, subsystems, services
- modsBySlotType = {}
- sFit = svcFit.getInstance()
- for module in fit.modules:
- modsBySlotType.setdefault(module.slot, []).append(module)
- modSection = []
- offineSuffix = ' /OFFLINE'
- mutants = {} # Format: {reference number: module}
- mutantReference = 1
- for slotType in EFT_SLOT_ORDER:
- rackLines = []
- modules = modsBySlotType.get(slotType, ())
- for module in modules:
- if module.item:
- mutated = bool(module.mutators)
- # if module was mutated, use base item name for export
- if mutated:
- modName = module.baseItem.name
- else:
- modName = module.item.name
- if mutated and mutations:
- mutants[mutantReference] = module
- mutationSuffix = ' [{}]'.format(mutantReference)
- mutantReference += 1
- else:
- mutationSuffix = ''
- modOfflineSuffix = offineSuffix if module.state == State.OFFLINE else ''
- if module.charge and sFit.serviceFittingOptions['exportCharges']:
- rackLines.append('{}, {}{}{}'.format(
- modName, module.charge.name, modOfflineSuffix, mutationSuffix))
- else:
- rackLines.append('{}{}{}'.format(modName, modOfflineSuffix, mutationSuffix))
- else:
- rackLines.append('[Empty {} slot]'.format(
- Slot.getName(slotType).capitalize() if slotType is not None else ''))
- if rackLines:
- modSection.append('\n'.join(rackLines))
- if modSection:
- sections.append('\n\n'.join(modSection))
-
- # Section 2: drones, fighters
- minionSection = []
- droneLines = []
- for drone in sorted(fit.drones, key=lambda d: d.item.name):
- droneLines.append('{} x{}'.format(drone.item.name, drone.amount))
- if droneLines:
- minionSection.append('\n'.join(droneLines))
- fighterLines = []
- for fighter in sorted(fit.fighters, key=lambda f: f.item.name):
- fighterLines.append('{} x{}'.format(fighter.item.name, fighter.amountActive))
- if fighterLines:
- minionSection.append('\n'.join(fighterLines))
- if minionSection:
- sections.append('\n\n'.join(minionSection))
-
- # Section 3: implants, boosters
- if implants:
- charSection = []
- implantLines = []
- for implant in fit.implants:
- implantLines.append(implant.item.name)
- if implantLines:
- charSection.append('\n'.join(implantLines))
- boosterLines = []
- for booster in fit.boosters:
- boosterLines.append(booster.item.name)
- if boosterLines:
- charSection.append('\n'.join(boosterLines))
- if charSection:
- sections.append('\n\n'.join(charSection))
-
- # Section 4: cargo
- cargoLines = []
- for cargo in sorted(
- fit.cargo,
- key=lambda c: (c.item.group.category.name, c.item.group.name, c.item.name)
- ):
- cargoLines.append('{} x{}'.format(cargo.item.name, cargo.amount))
- if cargoLines:
- sections.append('\n'.join(cargoLines))
-
- # Section 5: mutated modules' details
- mutationLines = []
- if mutants and mutations:
- 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))
- if mutationLines:
- sections.append('\n'.join(mutationLines))
-
- return '{}\n\n{}'.format(header, '\n\n\n'.join(sections))
+ def exportEft(cls, fit):
+ return EftPort.exportEft(fit, mutations=False, implants=False)
@classmethod
def exportEftImps(cls, fit):
- return cls.exportEft(fit, implants=True)
+ return EftPort.exportEft(fit, mutations=False, implants=True)
@staticmethod
def exportDna(fit):
@@ -1478,7 +1122,8 @@ class Port(object):
class PortProcessing(object):
- """Port Processing class """
+ """Port Processing class"""
+
@staticmethod
def backupFits(path, iportuser):
success = True