From ad03f907fae619786f520ed323d28228925e3eaf Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Fri, 12 Apr 2019 04:02:28 +0300 Subject: [PATCH] Overhaul module-related commands --- eos/effectHandlerHelpers.py | 28 ++-- gui/fitCommands/calc/fitAddModule.py | 100 +++++--------- gui/fitCommands/calc/fitAddProjectedModule.py | 92 +++---------- gui/fitCommands/calc/fitRemoveModule.py | 59 +++----- .../calc/fitRemoveProjectedModule.py | 29 +--- gui/fitCommands/calc/fitReplaceModule.py | 127 ++++++------------ gui/fitCommands/guiAddModule.py | 53 ++++---- gui/fitCommands/guiAddProjected.py | 6 +- gui/fitCommands/guiCargoToModule.py | 8 +- gui/fitCommands/guiFillWithModule.py | 12 +- gui/fitCommands/guiMetaSwap.py | 6 +- gui/fitCommands/guiModuleToCargo.py | 6 +- gui/fitCommands/guiMutaConvert.py | 16 ++- gui/fitCommands/guiMutaRevert.py | 13 +- gui/fitCommands/guiRemoveModule.py | 17 +-- gui/fitCommands/helpers.py | 86 +++++++++++- service/port/efs.py | 12 +- utils/repr.py | 10 ++ 18 files changed, 307 insertions(+), 373 deletions(-) create mode 100644 utils/repr.py diff --git a/eos/effectHandlerHelpers.py b/eos/effectHandlerHelpers.py index 5891c25e6..539328471 100644 --- a/eos/effectHandlerHelpers.py +++ b/eos/effectHandlerHelpers.py @@ -281,13 +281,18 @@ class HandledSsoCharacterList(list): class HandledProjectedModList(HandledList): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.lastOpState = None + def append(self, proj): if proj.isInvalid: # we must include it before we remove it. doing it this way ensures # rows and relationships in database are removed as well HandledList.append(self, proj) self.remove(proj) - return False + self.lastOpState = False + return proj.projected = True @@ -296,8 +301,9 @@ class HandledProjectedModList(HandledList): # Remove non-projectable modules if not proj.item.isType("projected") and not proj.isExclusiveSystemEffect: self.remove(proj) - return False - return True + self.lastOpState = False + return + self.lastOpState = True def insert(self, idx, proj): if proj.isInvalid: @@ -305,7 +311,8 @@ class HandledProjectedModList(HandledList): # rows and relationships in database are removed as well HandledList.insert(self, idx, proj) self.remove(proj) - return False + self.lastOpState = False + return proj.projected = True @@ -314,8 +321,9 @@ class HandledProjectedModList(HandledList): # Remove non-projectable modules if not proj.item.isType("projected") and not proj.isExclusiveSystemEffect: self.remove(proj) - return False - return True + self.lastOpState = False + return + self.lastOpState = True @property def currentSystemEffect(self): @@ -328,11 +336,13 @@ class HandledProjectedModList(HandledList): if mod: pyfalog.info("System effect occupied with {0}, removing it to make space for {1}".format(mod.item.name, proj.item.name)) - mutations = {m.attrID: m.value for m in mod.mutators.values()} position = self.index(mod) + # We need to pack up this info, so whatever... + from gui.fitCommands.helpers import ModuleInfo + modInfo = ModuleInfo.fromModule(mod) self.remove(mod) - return mod.itemID, mod.baseItemID, mod.mutaplasmidID, mutations, mod.state, mod.chargeID, position - return None, None, None, None, None, None, None + return position, modInfo + return None, None class HandledProjectedDroneList(HandledDroneCargoList): diff --git a/gui/fitCommands/calc/fitAddModule.py b/gui/fitCommands/calc/fitAddModule.py index 926eb0509..4f3cc3d7f 100644 --- a/gui/fitCommands/calc/fitAddModule.py +++ b/gui/fitCommands/calc/fitAddModule.py @@ -2,7 +2,6 @@ import wx from logbook import Logger import eos.db -from eos.saveddata.module import Module from gui.fitCommands.helpers import stateLimit from service.fit import Fit @@ -11,86 +10,55 @@ pyfalog = Logger(__name__) class FitAddModuleCommand(wx.Command): - """" - Fitting command that appends a module to a fit using the first available slot. In the case of a Subsystem, it checks - if there is already a subsystem with the same slot, and runs the replace command instead. - from sFit.appendModule - """ - def __init__(self, fitID, itemID, mutaplasmidID=None, baseID=None): - wx.Command.__init__(self, True) + def __init__(self, fitID, newModInfo): + wx.Command.__init__(self, True, 'Add Module') self.fitID = fitID - self.itemID = itemID - self.mutaplasmidID = mutaplasmidID - self.baseID = baseID - self.new_position = None - self.change = None - self.replace_cmd = None + self.newModInfo = newModInfo + self.savedPosition = None + self.subsystemCmd = None def Do(self): + pyfalog.debug('Doing addition of module {} to fit {}'.format(self.newModInfo, self.fitID)) sFit = Fit.getInstance() - fitID = self.fitID - itemID = self.itemID - fit = eos.db.getFit(fitID) - item = eos.db.getItem(itemID, eager=("attributes", "group.category")) + fit = sFit.getFit(self.fitID) - bItem = eos.db.getItem(self.baseID) if self.baseID else None - mItem = next((x for x in bItem.mutaplasmids if x.ID == self.mutaplasmidID)) if self.mutaplasmidID else None - - try: - self.module = Module(item, bItem, mItem) - except ValueError: - pyfalog.warning("Invalid module: {}", item) + newMod = self.newModInfo.toModule(fallbackState=stateLimit(self.newModInfo.itemID)) + if newMod is None: return False # If subsystem and we need to replace, run the replace command instead and bypass the rest of this command - if self.module.item.category.name == "Subsystem": - for mod in fit.modules: - if mod.getModifiedItemAttr("subSystemSlot") == self.module.getModifiedItemAttr("subSystemSlot"): + if newMod.item.category.name == 'Subsystem': + for oldMod in fit.modules: + if oldMod.getModifiedItemAttr('subSystemSlot') == newMod.getModifiedItemAttr('subSystemSlot') and newMod.slot == oldMod.slot: from .fitReplaceModule import FitReplaceModuleCommand - self.replace_cmd = FitReplaceModuleCommand( + self.subsystemCmd = FitReplaceModuleCommand( fitID=self.fitID, - position=mod.modPosition, - newItemID=itemID, - newBaseItemID=None, - newMutaplasmidID=None, - newMutations=None, - newState=None, - newChargeID=None) - return self.replace_cmd.Do() + position=oldMod.modPosition, + newModInfo=self.newModInfo) + return self.subsystemCmd.Do() - if self.module.fits(fit): - pyfalog.debug("Adding {} as module for fit {}", self.module, fit) - self.module.owner = fit - numSlots = len(fit.modules) - fit.modules.append(self.module) - desiredState = stateLimit(self.module.item) - if self.module.isValidState(desiredState): - self.module.state = desiredState - - # todo: fix these - # As some items may affect state-limiting attributes of the ship, calculate new attributes first - # self.recalc(fit) - # Then, check states of all modules and change where needed. This will recalc if needed - sFit.checkStates(fit, self.module) - - # fit.fill() - eos.db.commit() - - self.change = numSlots != len(fit.modules) - self.new_position = self.module.modPosition - else: + if not newMod.fits(fit): + pyfalog.warning('Module does not fit') + self.Undo() return False + newMod.owner = fit + fit.modules.append(newMod) + + sFit.checkStates(fit, newMod) + + eos.db.commit() + self.savedPosition = newMod.modPosition return True def Undo(self): + pyfalog.debug('Undoing addition of module {} to fit {}'.format(self.newModInfo, self.fitID)) # We added a subsystem module, which actually ran the replace command. Run the undo for that guy instead - if self.replace_cmd: - return self.replace_cmd.Undo() - - from .fitRemoveModule import FitRemoveModuleCommand # Avoid circular import - if self.new_position: - cmd = FitRemoveModuleCommand(self.fitID, [self.new_position]) - cmd.Do() - return True + if self.subsystemCmd is not None: + return self.subsystemCmd.Undo() + from .fitRemoveModule import FitRemoveModuleCommand + if self.savedPosition is None: + return False + cmd = FitRemoveModuleCommand(self.fitID, [self.savedPosition]) + return cmd.Do() diff --git a/gui/fitCommands/calc/fitAddProjectedModule.py b/gui/fitCommands/calc/fitAddProjectedModule.py index 03827dda4..cf9eae055 100644 --- a/gui/fitCommands/calc/fitAddProjectedModule.py +++ b/gui/fitCommands/calc/fitAddProjectedModule.py @@ -3,105 +3,57 @@ from logbook import Logger import eos.db from eos.const import FittingModuleState -from eos.saveddata.module import Module -from gui.fitCommands.helpers import ModuleInfoCache from service.fit import Fit -from service.market import Market pyfalog = Logger(__name__) class FitAddProjectedModuleCommand(wx.Command): - """" - from sFit.project - """ - def __init__(self, fitID, newItemID, newBaseItemID, newMutaplasmidID, newMutations, newState, newChargeID, newPosition): + + def __init__(self, fitID, newModInfo, newPosition=None): wx.Command.__init__(self, True) self.fitID = fitID - self.newItemID = newItemID - self.newBaseItemID = newBaseItemID - self.newMutaplasmidID = newMutaplasmidID - self.newMutations = newMutations - self.newState = newState - self.newChargeID = newChargeID + self.newModInfo = newModInfo self.newPosition = newPosition - self.oldModuleInfo = None + self.oldModInfo = None + self.oldPosition = None def Do(self): - pyfalog.debug("Projecting fit ({0}) onto: {1}", self.fitID, self.newItemID) + pyfalog.debug('Doing projection of module {} onto: {}'.format(self.newModInfo, self.fitID)) fit = Fit.getInstance().getFit(self.fitID) - mod = self.makeModule(self.newItemID, self.newBaseItemID, self.newMutaplasmidID, self.newMutations, self.newState, self.newChargeID) - if mod is None: + newMod = self.newModInfo.toModule(fallbackState=FittingModuleState.ACTIVE) + if newMod is None: return False - if not mod.canHaveState(mod.state, fit): - mod.state = FittingModuleState.OFFLINE + if not newMod.canHaveState(newMod.state, fit): + newMod.state = FittingModuleState.OFFLINE - oldItemID, oldBaseItemID, oldMutaplasmidID, oldMutations, oldState, oldChargeID, oldPosition = fit.projectedModules.makeRoom(mod) - if oldItemID is not None: - self.oldModuleInfo = ModuleInfoCache(oldPosition, oldItemID, oldState, oldChargeID, oldBaseItemID, oldMutaplasmidID, oldMutations) + self.oldPosition, self.oldModInfo = fit.projectedModules.makeRoom(newMod) if self.newPosition is not None: - if not fit.projectedModules.insert(self.newPosition, mod): + fit.projectedModules.insert(self.newPosition, newMod) + if not fit.projectedModules.lastOpState: + self.Undo() return False else: - if not fit.projectedModules.append(mod): + fit.projectedModules.append(newMod) + if not fit.projectedModules.lastOpState: + self.Undo() return False - self.newPosition = fit.projectedModules.index(mod) + self.newPosition = fit.projectedModules.index(newMod) eos.db.commit() return True def Undo(self): - if self.oldModuleInfo is not None: + if self.oldPosition is not None and self.oldModInfo is not None: cmd = FitAddProjectedModuleCommand( fitID=self.fitID, - newItemID=self.oldModuleInfo.itemID, - newBaseItemID=self.oldModuleInfo.baseID, - newMutaplasmidID=self.oldModuleInfo.mutaplasmidID, - newMutations=self.oldModuleInfo.mutations, - newState=self.oldModuleInfo.state, - newChargeID=self.oldModuleInfo.chargeID, - newPosition=self.oldModuleInfo.modPosition) + newModInfo=self.oldModInfo, + newPosition=self.oldPosition) return cmd.Do() - from gui.fitCommands.calc.fitRemoveProjectedModule import FitRemoveProjectedModuleCommand # avoids circular import + from gui.fitCommands.calc.fitRemoveProjectedModule import FitRemoveProjectedModuleCommand cmd = FitRemoveProjectedModuleCommand(self.fitID, self.newPosition) cmd.Do() return True - - def makeModule(self, itemID, baseItemID, mutaplasmidID, mutations, state, chargeID): - mkt = Market.getInstance() - - item = mkt.getItem(itemID, eager=("attributes", "group.category")) - if baseItemID and mutaplasmidID: - baseItem = mkt.getItem(baseItemID, eager=("attributes", "group.category")) - mutaplasmid = eos.db.getDynamicItem(mutaplasmidID) - else: - baseItem = None - mutaplasmid = None - try: - mod = Module(item, baseItem, mutaplasmid) - except ValueError: - pyfalog.warning("Invalid item: {0}", itemID) - return None - - for attrID, mutator in mod.mutators.items(): - if attrID in mutations: - mutator.value = mutations[attrID] - - if state is not None: - if not mod.isValidState(state): - return None - mod.state = state - else: - desiredState = FittingModuleState.ACTIVE - if mod.isValidState(desiredState): - mod.state = desiredState - - if chargeID is not None: - charge = mkt.getItem(chargeID) - if charge is not None: - mod.charge = charge - - return mod diff --git a/gui/fitCommands/calc/fitRemoveModule.py b/gui/fitCommands/calc/fitRemoveModule.py index 20dcd5220..b9642e831 100644 --- a/gui/fitCommands/calc/fitRemoveModule.py +++ b/gui/fitCommands/calc/fitRemoveModule.py @@ -2,66 +2,41 @@ import wx from logbook import Logger import eos.db -from gui.fitCommands.helpers import ModuleInfoCache +from gui.fitCommands.helpers import ModuleInfo +from service.fit import Fit pyfalog = Logger(__name__) class FitRemoveModuleCommand(wx.Command): - """" - Fitting command that removes a module at a specified positions - from sFit.removeModule - """ - def __init__(self, fitID: int, positions: list = None): - wx.Command.__init__(self, True) + def __init__(self, fitID, positions): + wx.Command.__init__(self, True, 'Remove Module') self.fitID = fitID self.positions = positions - self.modCache = [] - self.change = None + self.oldModInfos = {} def Do(self): - fitID = self.fitID - fit = eos.db.getFit(fitID) + pyfalog.debug('Doing removal of modules from positions {} on fit {}'.format(self.positions, self.fitID)) + fit = Fit.getInstance().getFit(self.fitID) - pyfalog.debug("Removing module from position ({0}) for fit ID: {1}", self.positions, fitID) - - for x in self.positions: - mod = fit.modules[x] + for position in self.positions: + mod = fit.modules[position] if not mod.isEmpty: - pyfalog.debug(" -- Removing {}", mod) - self.modCache.append(ModuleInfoCache( - mod.modPosition, - mod.item.ID, - mod.state, - mod.chargeID, - mod.baseItemID, - mod.mutaplasmidID, - {m.attrID: m.value for m in mod.mutators.values()})) - fit.modules.toDummy(x) + self.oldModInfos[position] = ModuleInfo.fromModule(mod) + fit.modules.toDummy(position) - # if no modules have changes, skip command - if not len(self.modCache) > 0: + # If no modules were removed, report that command was not completed + if not len(self.oldModInfos) > 0: return False - eos.db.commit() return True def Undo(self): - pyfalog.debug("Reapplying {} removed module(s) for {}", len(self.modCache), self.fitID) - - from gui.fitCommands.calc.fitReplaceModule import FitReplaceModuleCommand # avoids circular import - for modInfo in self.modCache: - pyfalog.debug(" -- {}", modInfo) - cmd = FitReplaceModuleCommand( - fitID=self.fitID, - position=modInfo.modPosition, - newItemID=modInfo.itemID, - newBaseItemID=modInfo.baseID, - newMutaplasmidID=modInfo.mutaplasmidID, - newMutations=modInfo.mutations, - newState=modInfo.state, - newChargeID=modInfo.chargeID) + pyfalog.debug('Undoing removal of modules {} on fit {}'.format(self.oldModInfos, self.fitID)) + from gui.fitCommands.calc.fitReplaceModule import FitReplaceModuleCommand + for position, modInfo in self.oldModInfos.items(): + cmd = FitReplaceModuleCommand(fitID=self.fitID, position=position, newModInfo=modInfo) cmd.Do() return True diff --git a/gui/fitCommands/calc/fitRemoveProjectedModule.py b/gui/fitCommands/calc/fitRemoveProjectedModule.py index ecc65c6a2..30e20c8a1 100644 --- a/gui/fitCommands/calc/fitRemoveProjectedModule.py +++ b/gui/fitCommands/calc/fitRemoveProjectedModule.py @@ -3,16 +3,14 @@ from logbook import Logger import eos.db from service.fit import Fit -from gui.fitCommands.helpers import ModuleInfoCache +from gui.fitCommands.helpers import ModuleInfo pyfalog = Logger(__name__) class FitRemoveProjectedModuleCommand(wx.Command): - """" - from sFit.project - """ + def __init__(self, fitID, position): wx.Command.__init__(self, True) self.fitID = fitID @@ -23,17 +21,8 @@ class FitRemoveProjectedModuleCommand(wx.Command): pyfalog.debug("Removing ({}) onto: {}".format(self.fitID, self.position)) fit = Fit.getInstance().getFit(self.fitID) mod = fit.projectedModules[self.position] - self.savedModInfo = ModuleInfoCache( - modPosition=self.position, - itemID=mod.itemID, - state=mod.state, - chargeID=mod.chargeID, - baseID=None, - mutaplasmidID=None, - mutations={}) - + self.savedModInfo = ModuleInfo.fromModule(mod) del fit.projectedModules[self.position] - eos.db.commit() return True @@ -41,12 +30,6 @@ class FitRemoveProjectedModuleCommand(wx.Command): from gui.fitCommands.calc.fitAddProjectedModule import FitAddProjectedModuleCommand cmd = FitAddProjectedModuleCommand( fitID=self.fitID, - newItemID=self.savedModInfo.itemID, - newBaseItemID=self.savedModInfo.baseID, - newMutaplasmidID=self.savedModInfo.mutaplasmidID, - newMutations=self.savedModInfo.mutations, - newState=self.savedModInfo.state, - newChargeID=self.savedModInfo.chargeID, - newPosition=self.savedModInfo.modPosition) - cmd.Do() - return True + newModInfo=self.savedModInfo, + newPosition=self.position) + return cmd.Do() diff --git a/gui/fitCommands/calc/fitReplaceModule.py b/gui/fitCommands/calc/fitReplaceModule.py index 00152e44d..6f0cd41e7 100644 --- a/gui/fitCommands/calc/fitReplaceModule.py +++ b/gui/fitCommands/calc/fitReplaceModule.py @@ -2,113 +2,64 @@ import wx from logbook import Logger import eos.db -from eos.saveddata.module import Module -from gui.fitCommands.helpers import ModuleInfoCache, stateLimit +from gui.fitCommands.helpers import ModuleInfo, stateLimit from service.fit import Fit -from service.market import Market + pyfalog = Logger(__name__) class FitReplaceModuleCommand(wx.Command): - """" - Fitting command that changes an existing module into another. - from sFit.changeModule - """ - def __init__(self, fitID, position, newItemID, newBaseItemID, newMutaplasmidID, newMutations, newState, newChargeID): - wx.Command.__init__(self, True, "Change Module") + def __init__(self, fitID, position, newModInfo): + wx.Command.__init__(self, True, 'Replace Module') self.fitID = fitID self.position = position - self.newItemID = newItemID - self.newBaseItemID = newBaseItemID - self.newMutaplasmidID = newMutaplasmidID - self.newMutations = newMutations - self.newState = newState - self.newChargeID = newChargeID - self.oldModuleInfo = None + self.newModInfo = newModInfo + self.oldModInfo = None def Do(self): - fit = Fit.getInstance().getFit(self.fitID) - mod = fit.modules[self.position] - if not mod.isEmpty: - self.oldModuleInfo = ModuleInfoCache( - mod.modPosition, - mod.item.ID, - mod.state, - mod.chargeID, - mod.baseItemID, - mod.mutaplasmidID, - {m.attrID: m.value for m in mod.mutators.values()}) - - newState = self.newState if self.newState is not None else getattr(self.oldModuleInfo, 'state', None) - newChargeID = self.newChargeID if self.newChargeID is not None else getattr(self.oldModuleInfo, 'chargeID', None) - return self.changeModule(self.newItemID, self.newBaseItemID, self.newMutaplasmidID, self.newMutations, newState, newChargeID) - - def Undo(self): - if self.oldModuleInfo is None: - fit = Fit.getInstance().getFit(self.fitID) - fit.modules.toDummy(self.position) - return True - return self.changeModule( - self.oldModuleInfo.itemID, - self.oldModuleInfo.baseID, - self.oldModuleInfo.mutaplasmidID, - self.oldModuleInfo.mutations, - self.oldModuleInfo.state, - self.oldModuleInfo.chargeID) - - def changeModule(self, itemID, baseItemID, mutaplasmidID, mutations, state, chargeID): - fit = Fit.getInstance().getFit(self.fitID) + pyfalog.debug('Doing replacement of module to {} on fit {}'.format(self.newModInfo, self.fitID)) + sFit = Fit.getInstance() + fit = sFit.getFit(self.fitID) oldMod = fit.modules[self.position] - - pyfalog.debug("Changing module on position ({0}) for fit ID: {1}", self.position, self.fitID) - - mkt = Market.getInstance() - item = mkt.getItem(itemID, eager=("attributes", "group.category")) - if baseItemID and mutaplasmidID: - baseItem = mkt.getItem(baseItemID, eager=("attributes", "group.category")) - mutaplasmid = eos.db.getDynamicItem(mutaplasmidID) - else: - baseItem = None - mutaplasmid = None - - try: - newMod = Module(item, baseItem, mutaplasmid) - except ValueError: - pyfalog.warning("Invalid item: {0}", itemID) + if not oldMod.isEmpty: + self.oldModInfo = ModuleInfo.fromModule(oldMod) + newMod = self.newModInfo.toModule(fallbackState=stateLimit(self.newModInfo.itemID)) + if newMod is None: return False - - if newMod.slot != oldMod.slot: - return False - - for attrID, mutator in newMod.mutators.items(): - if attrID in mutations: - mutator.value = mutations[attrID] - # Dummy it out in case the next bit fails fit.modules.toDummy(self.position) - if not newMod.fits(fit): + pyfalog.warning('Module does not fit') self.Undo() return False - newMod.owner = fit fit.modules.toModule(self.position, newMod) - - if state is not None: - if not newMod.isValidState(state): - return False - newMod.state = state - else: - desiredState = stateLimit(newMod.item) if state is None else state - if newMod.isValidState(desiredState): - newMod.state = desiredState - - if chargeID is not None: - charge = mkt.getItem(chargeID) - if charge is not None: - newMod.charge = charge - + sFit.checkStates(fit, newMod) + eos.db.commit() + return True + + def Undo(self): + pyfalog.debug('Undoing replacement of module from {} to {} on fit {}'.format(self.oldModInfo, self.newModInfo, self.fitID)) + # Remove if there was no module + if self.oldModInfo is None: + from gui.fitCommands.calc.fitRemoveModule import FitRemoveModuleCommand + cmd = FitRemoveModuleCommand(self.fitID, [self.position]) + return cmd.Do() + # Replace if there was + sFit = Fit.getInstance() + fit = sFit.getFit(self.fitID) + oldMod = self.oldModInfo.toModule() + if oldMod is None: + return False + fit.modules.toDummy(self.position) + if not oldMod.fits(fit): + pyfalog.warning('Module does not fit') + self.Do() + return False + oldMod.owner = fit + fit.modules.toModule(self.position, oldMod) + sFit.checkStates(fit, oldMod) eos.db.commit() return True diff --git a/gui/fitCommands/guiAddModule.py b/gui/fitCommands/guiAddModule.py index 28b60910d..1e386206a 100644 --- a/gui/fitCommands/guiAddModule.py +++ b/gui/fitCommands/guiAddModule.py @@ -1,16 +1,21 @@ import wx -import eos.db +from logbook import Logger + import gui.mainFrame +from service.market import Market +from service.fit import Fit from gui import globalEvents as GE +from gui.fitCommands.helpers import ModuleInfo from .calc.fitAddModule import FitAddModuleCommand from .calc.fitReplaceModule import FitReplaceModuleCommand from .calc.fitSetCharge import FitSetChargeCommand -from service.fit import Fit -from logbook import Logger + + pyfalog = Logger(__name__) class GuiModuleAddCommand(wx.Command): + def __init__(self, fitID, itemID, position=None): """ Handles adding an item, usually a module, to the Fitting Window. @@ -20,57 +25,51 @@ class GuiModuleAddCommand(wx.Command): set the charge on the underlying module (requires position) :param position: Optional. The position in fit.modules that we are attempting to set the item to """ - wx.Command.__init__(self, True, "Module Add: {}".format(itemID)) - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - self.sFit = Fit.getInstance() + wx.Command.__init__(self, True, 'Module Add') self.fitID = fitID self.itemID = itemID - self.internal_history = wx.CommandProcessor() self.position = position - self.old_mod = None + self.internalHistory = wx.CommandProcessor() def Do(self): pyfalog.debug("{} Do()".format(self)) success = False - item = eos.db.getItem(self.itemID) + item = Market.getInstance().getItem(self.itemID) + # Charge if item.isCharge and self.position is not None: pyfalog.debug("Trying to add a charge") - success = self.internal_history.Submit(FitSetChargeCommand(self.fitID, [self.position], self.itemID)) + success = self.internalHistory.Submit(FitSetChargeCommand(self.fitID, [self.position], self.itemID)) if not success: pyfalog.debug(" Failed") return False # if it's a charge item and this failed, nothing more we can try. - # if we have a position set, try to apply the module to that position + # Module to position elif self.position is not None: pyfalog.debug("Trying to add a module to a specific position") - success = self.internal_history.Submit(FitReplaceModuleCommand( + success = self.internalHistory.Submit(FitReplaceModuleCommand( fitID=self.fitID, position=self.position, - newItemID=self.itemID, - newBaseItemID=None, - newMutaplasmidID=None, - newMutations=None, - newState=None, - newChargeID=None)) + newModInfo=ModuleInfo(itemID=self.itemID))) if not success: pyfalog.debug(" Failed") # something went wrong with trying to fit the module into specific location, attempt to append it self.position = None - - # if we're not trying to set module to a position, simply append + # Module without position if self.position is None: pyfalog.debug("Trying to append a module") - success = self.internal_history.Submit(FitAddModuleCommand(self.fitID, self.itemID)) + success = self.internalHistory.Submit(FitAddModuleCommand( + fitID=self.fitID, + newModInfo=ModuleInfo(itemID=self.itemID))) if success: - self.sFit.recalc(self.fitID) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="modadd", typeID=self.itemID)) + Fit.getInstance().recalc(self.fitID) + wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), GE.FitChanged(fitID=self.fitID, action="modadd", typeID=self.itemID)) return True return False def Undo(self): pyfalog.debug("{} Undo()".format(self)) - for _ in self.internal_history.Commands: - self.internal_history.Undo() - self.sFit.recalc(self.fitID) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=self.itemID)) + for _ in self.internalHistory.Commands: + self.internalHistory.Undo() + Fit.getInstance().recalc(self.fitID) + wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), GE.FitChanged(fitID=self.fitID, action="moddel", typeID=self.itemID)) return True diff --git a/gui/fitCommands/guiAddProjected.py b/gui/fitCommands/guiAddProjected.py index 769d1cd71..43b604f5e 100644 --- a/gui/fitCommands/guiAddProjected.py +++ b/gui/fitCommands/guiAddProjected.py @@ -3,7 +3,7 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE -from eos.saveddata.module import Module +from gui.fitCommands.helpers import ModuleInfo from .calc.fitAddProjectedModule import FitAddProjectedModuleCommand from .calc.fitAddProjectedFit import FitAddProjectedFitCommand from .calc.fitAddProjectedFighter import FitAddProjectedFighterCommand @@ -35,7 +35,9 @@ class GuiAddProjectedCommand(wx.Command): elif item.category.name == "Fighter": result = self.internal_history.Submit(FitAddProjectedFighterCommand(self.fitID, self.id, None, None)) else: - result = self.internal_history.Submit(FitAddProjectedModuleCommand(self.fitID, self.id, None, None, None, None, None, None)) + result = self.internal_history.Submit(FitAddProjectedModuleCommand( + fitID=self.fitID, + newModInfo=ModuleInfo(itemID=self.id))) elif self.type == 'fit': result = self.internal_history.Submit(FitAddProjectedFitCommand(self.fitID, self.id, None)) diff --git a/gui/fitCommands/guiCargoToModule.py b/gui/fitCommands/guiCargoToModule.py index 0b5fcfd6b..48c693818 100644 --- a/gui/fitCommands/guiCargoToModule.py +++ b/gui/fitCommands/guiCargoToModule.py @@ -6,6 +6,7 @@ from gui import globalEvents as GE from gui.fitCommands.calc.fitSetCharge import FitSetChargeCommand from gui.fitCommands.calc.fitReplaceModule import FitReplaceModuleCommand from gui.fitCommands.calc.fitRemoveCargo import FitRemoveCargoCommand +from gui.fitCommands.helpers import ModuleInfo from .calc.fitAddCargo import FitAddCargoCommand from logbook import Logger pyfalog = Logger(__name__) @@ -47,12 +48,7 @@ class GuiCargoToModuleCommand(wx.Command): self.addCmd = FitReplaceModuleCommand( fitID=self.fitID, position=module.modPosition, - newItemID=cargo.itemID, - newBaseItemID=None, - newMutaplasmidID=None, - newMutations=None, - newState=None, - newChargeID=None) + newModInfo=ModuleInfo(itemID=cargo.itemID)) result = self.internal_history.Submit(self.addCmd) diff --git a/gui/fitCommands/guiFillWithModule.py b/gui/fitCommands/guiFillWithModule.py index 5b7bf95e3..d8cf097c6 100644 --- a/gui/fitCommands/guiFillWithModule.py +++ b/gui/fitCommands/guiFillWithModule.py @@ -1,9 +1,13 @@ import wx +from logbook import Logger + import gui.mainFrame from gui import globalEvents as GE -from .calc.fitAddModule import FitAddModuleCommand +from gui.fitCommands.helpers import ModuleInfo from service.fit import Fit -from logbook import Logger +from .calc.fitAddModule import FitAddModuleCommand + + pyfalog = Logger(__name__) @@ -30,10 +34,8 @@ class GuiFillWithModuleCommand(wx.Command): pyfalog.debug("{} Do()".format(self)) pyfalog.debug("Trying to append a module") added_modules = 0 - success = self.internal_history.Submit(FitAddModuleCommand(self.fitID, self.itemID)) - while (success): + while self.internal_history.Submit(FitAddModuleCommand(fitID=self.fitID, newModInfo=ModuleInfo(itemID=self.itemID))): added_modules += 1 - success = self.internal_history.Submit(FitAddModuleCommand(self.fitID, self.itemID)) if added_modules > 0: self.sFit.recalc(self.fitID) diff --git a/gui/fitCommands/guiMetaSwap.py b/gui/fitCommands/guiMetaSwap.py index 1e41ba189..fc587e669 100644 --- a/gui/fitCommands/guiMetaSwap.py +++ b/gui/fitCommands/guiMetaSwap.py @@ -3,6 +3,7 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE +from gui.fitCommands.helpers import ModuleInfo from .calc.fitRemoveImplant import FitRemoveImplantCommand from .calc.fitAddImplant import FitAddImplantCommand from .calc.fitRemoveBooster import FitRemoveBoosterCommand @@ -30,9 +31,8 @@ class GuiMetaSwapCommand(wx.Command): if context == 'fittingModule': for x in selection: position = fit.modules.index(x) - state = x.state - chargeID = x.chargeID - self.data.append(((FitReplaceModuleCommand, fitID, position, itemID, None, None, None, state, chargeID),),) + self.data.append(((FitReplaceModuleCommand, fitID, position, ModuleInfo( + itemID=itemID, chargeID=x.chargeID, state=x.state, spoolType=x.spoolType, spoolAmount=x.spoolAmount)),),) elif context == 'implantItem': for x in selection: idx = fit.implants.index(x) diff --git a/gui/fitCommands/guiModuleToCargo.py b/gui/fitCommands/guiModuleToCargo.py index bb62ab05a..a00866df2 100644 --- a/gui/fitCommands/guiModuleToCargo.py +++ b/gui/fitCommands/guiModuleToCargo.py @@ -6,6 +6,7 @@ from gui import globalEvents as GE from gui.fitCommands.calc.fitRemoveCargo import FitRemoveCargoCommand from gui.fitCommands.calc.fitRemoveModule import FitRemoveModuleCommand from gui.fitCommands.calc.fitReplaceModule import FitReplaceModuleCommand +from gui.fitCommands.helpers import ModuleInfo from service.fit import Fit from .calc.fitAddCargo import FitAddCargoCommand @@ -37,7 +38,10 @@ class GuiModuleToCargoCommand(wx.Command): else: # otherwise, try to swap by replacing module with cargo item. If successful, remove old cargo and add new cargo cargo = fit.cargo[self.cargoIdx] - self.modReplaceCmd = FitReplaceModuleCommand(self.fitID, module.modPosition, cargo.itemID) + self.modReplaceCmd = FitReplaceModuleCommand( + fitID=self.fitID, + position=module.modPosition, + newModInfo=ModuleInfo(itemID=cargo.itemID)) result = self.internal_history.Submit(self.modReplaceCmd) diff --git a/gui/fitCommands/guiMutaConvert.py b/gui/fitCommands/guiMutaConvert.py index be7b2580f..0a96147e8 100644 --- a/gui/fitCommands/guiMutaConvert.py +++ b/gui/fitCommands/guiMutaConvert.py @@ -2,6 +2,7 @@ import wx import gui.mainFrame from gui import globalEvents as GE +from gui.fitCommands.helpers import ModuleInfo from service.fit import Fit from .calc.fitReplaceModule import FitReplaceModuleCommand @@ -28,12 +29,15 @@ class GuiMutaConvertCommand(wx.Command): success = self.internal_history.Submit(FitReplaceModuleCommand( fitID=self.fitID, position=self.position, - newItemID=self.mutaplasmid.resultingItem.ID, - newBaseItemID=oldMod.item.ID, - newMutaplasmidID=self.mutaplasmid.ID, - newMutations={}, - newState=oldMod.state, - newChargeID=oldMod.chargeID)) + newModInfo=ModuleInfo( + itemID=self.mutaplasmid.resultingItem.ID, + baseItemID=oldMod.item.ID, + mutaplasmidID=self.mutaplasmid.ID, + mutations={}, + chargeID=oldMod.chargeID, + state=oldMod.state, + spoolType=oldMod.spoolType, + spoolAmount=oldMod.spoolAmount))) if not success: return False diff --git a/gui/fitCommands/guiMutaRevert.py b/gui/fitCommands/guiMutaRevert.py index 74d9a46e3..b2cf391f0 100644 --- a/gui/fitCommands/guiMutaRevert.py +++ b/gui/fitCommands/guiMutaRevert.py @@ -2,6 +2,7 @@ import wx import gui.mainFrame from gui import globalEvents as GE +from gui.fitCommands.helpers import ModuleInfo from service.fit import Fit from .calc.fitReplaceModule import FitReplaceModuleCommand @@ -27,12 +28,12 @@ class GuiMutaRevertCommand(wx.Command): success = self.internal_history.Submit(FitReplaceModuleCommand( fitID=self.fitID, position=self.position, - newItemID=oldMod.baseItemID, - newBaseItemID=None, - newMutaplasmidID=None, - newMutations=None, - newState=oldMod.state, - newChargeID=oldMod.chargeID)) + newModInfo=ModuleInfo( + itemID=oldMod.baseItemID, + chargeID=oldMod.chargeID, + state=oldMod.state, + spoolType=oldMod.spoolType, + spoolAmount=oldMod.spoolAmount))) if not success: return False diff --git a/gui/fitCommands/guiRemoveModule.py b/gui/fitCommands/guiRemoveModule.py index d2e3afe43..939e219ed 100644 --- a/gui/fitCommands/guiRemoveModule.py +++ b/gui/fitCommands/guiRemoveModule.py @@ -3,7 +3,7 @@ from service.fit import Fit import gui.mainFrame from gui import globalEvents as GE -from .helpers import ModuleInfoCache +from .helpers import ModuleInfo from .calc.fitRemoveModule import FitRemoveModuleCommand @@ -19,22 +19,15 @@ class GuiModuleRemoveCommand(wx.Command): self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.sFit = Fit.getInstance() self.fitID = fitID - self.modCache = [ModuleInfoCache( - mod.modPosition, - mod.item.ID, - mod.state, - mod.chargeID, - mod.baseItemID, - mod.mutaplasmidID, - {m.attrID: m.value for m in mod.mutators.values()}) for mod in modules if not mod.isEmpty] + self.modCache = {mod.modPosition: ModuleInfo.fromModule(mod) for mod in modules if not mod.isEmpty} self.internal_history = wx.CommandProcessor() def Do(self): - success = self.internal_history.Submit(FitRemoveModuleCommand(self.fitID, [mod.modPosition for mod in self.modCache])) + success = self.internal_history.Submit(FitRemoveModuleCommand(self.fitID, [pos for pos in self.modCache])) if success: self.sFit.recalc(self.fitID) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=set([mod.itemID for mod in self.modCache]))) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="moddel", typeID=set([mod.itemID for mod in self.modCache.values()]))) return True return False @@ -42,5 +35,5 @@ class GuiModuleRemoveCommand(wx.Command): for _ in self.internal_history.Commands: self.internal_history.Undo() self.sFit.recalc(self.fitID) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="modadd", typeID=set([mod.itemID for mod in self.modCache]))) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.fitID, action="modadd", typeID=set([mod.itemID for mod in self.modCache.values()]))) return True diff --git a/gui/fitCommands/helpers.py b/gui/fitCommands/helpers.py index 44c25c5f1..9b0e690a2 100644 --- a/gui/fitCommands/helpers.py +++ b/gui/fitCommands/helpers.py @@ -1,12 +1,92 @@ -from collections import namedtuple +from logbook import Logger +import eos.db from eos.const import FittingModuleState +from eos.saveddata.module import Module +from service.market import Market +from utils.repr import makeReprStr -ModuleInfoCache = namedtuple('ModuleInfoCache', ['modPosition', 'itemID', 'state', 'chargeID', 'baseID', 'mutaplasmidID', 'mutations']) +pyfalog = Logger(__name__) -def stateLimit(item): +class ModuleInfo: + + def __init__(self, itemID, baseItemID=None, mutaplasmidID=None, mutations=None, chargeID=None, state=None, spoolType=None, spoolAmount=None): + self.itemID = itemID + self.baseItemID = baseItemID + self.mutaplasmidID = mutaplasmidID + self.mutations = mutations + self.chargeID = chargeID + self.state = state + self.spoolType = spoolType + self.spoolAmount = spoolAmount + + @classmethod + def fromModule(cls, mod): + if mod is None: + return None + info = cls( + itemID=mod.itemID, + baseItemID=mod.baseItemID, + mutaplasmidID=mod.mutaplasmidID, + mutations={m.attrID: m.value for m in mod.mutators.values()}, + chargeID=mod.chargeID, + state=mod.state, + spoolType=mod.spoolType, + spoolAmount=mod.spoolAmount) + return info + + def toModule(self, fallbackState=None): + mkt = Market.getInstance() + + item = mkt.getItem(self.itemID, eager=('attributes', 'group.category')) + if self.baseItemID and self.mutaplasmidID: + baseItem = mkt.getItem(self.baseItemID, eager=('attributes', 'group.category')) + mutaplasmid = eos.db.getDynamicItem(self.mutaplasmidID) + else: + baseItem = None + mutaplasmid = None + try: + mod = Module(item, baseItem, mutaplasmid) + except ValueError: + pyfalog.warning('Invalid item: {}'.format(self.itemID)) + return None + + for attrID, mutator in mod.mutators.items(): + if attrID in self.mutations: + mutator.value = self.mutations[attrID] + + if self.spoolType is not None and self.spoolAmount is not None: + mod.spoolType = self.spoolType + mod.spoolAmount = self.spoolAmount + + if self.state is not None: + if not mod.isValidState(self.state): + pyfalog.warning('Cannot set state {}'.format(self.state)) + return None + mod.state = self.state + elif fallbackState is not None: + if mod.isValidState(fallbackState): + mod.state = fallbackState + + if self.chargeID is not None: + charge = mkt.getItem(self.chargeID) + if charge is None: + pyfalog.warning('Cannot set charge {}'.format(self.chargeID)) + return None + mod.charge = charge + + return mod + + def __repr__(self): + return makeReprStr(self, [ + 'itemID', 'baseItemID', 'mutaplasmidID', 'mutations', + 'chargeID', 'state', 'spoolType', 'spoolAmount']) + + +def stateLimit(itemIdentity): + item = Market.getInstance().getItem(itemIdentity) if {'moduleBonusAssaultDamageControl', 'moduleBonusIndustrialInvulnerability'}.intersection(item.effects): return FittingModuleState.ONLINE return FittingModuleState.ACTIVE diff --git a/service/port/efs.py b/service/port/efs.py index 71ea9660f..3fbfe744c 100755 --- a/service/port/efs.py +++ b/service/port/efs.py @@ -1,8 +1,10 @@ import json -import eos.db - from math import log from numbers import Number + +from logbook import Logger + +import eos.db from config import version as pyfaVersion from service.fit import Fit from service.market import Market @@ -16,7 +18,9 @@ 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 +from gui.fitCommands.helpers import ModuleInfo + + pyfalog = Logger(__name__) @@ -62,7 +66,7 @@ class EfsPort: if propID is None: return None - FitAddModuleCommand(fitID, propID).Do() + FitAddModuleCommand(fitID, ModuleInfo(itemID=propID)).Do() sFit.recalc(fit) fit = eos.db.getFit(fitID) mwdPropSpeed = fit.maxSpeed diff --git a/utils/repr.py b/utils/repr.py new file mode 100644 index 000000000..107e27ec2 --- /dev/null +++ b/utils/repr.py @@ -0,0 +1,10 @@ +def makeReprStr(instance, spec=None): + arg_list = [] + for field in spec or (): + if isinstance(field, str): + repr_name, attr_name = field, field + else: + repr_name, attr_name = field + attr_val = getattr(instance, attr_name, 'N/A') + arg_list.append('{}={}'.format(repr_name, attr_val)) + return '<{}({})>'.format(type(instance).__name__, ', '.join(arg_list))