def calculateModifiedAttributes(self, targetFit=None, withBoosters=False, dirtyStorage=None): timer = Timer(u'Fit: {}, {}'.format(self.ID, self.name), logger) logger.debug("Starting fit calculation on: %r, withBoosters: %s", self, withBoosters) shadow = False if targetFit: logger.debug("Applying projections to target: %r", targetFit) projectionInfo = self.getProjectionInfo(targetFit.ID) logger.debug("ProjectionInfo: %s", projectionInfo) if self == targetFit: copied = self # original fit shadow = True self = copy.deepcopy(self) self.fleet = copied.fleet logger.debug("Handling self projection - making shadow copy of fit. %r => %r", copied, self) # we delete the fit because when we copy a fit, flush() is # called to properly handle projection updates. However, we do # not want to save this fit to the database, so simply remove it eos.db.saveddata_session.delete(self) if self.fleet is not None and withBoosters is True: logger.debug("Fleet is set, gathering gang boosts") self.gangBoosts = self.fleet.recalculateLinear(withBoosters=withBoosters) timer.checkpoint("Done calculating gang boosts for %r"%self) elif self.fleet is None: self.gangBoosts = None # If we're not explicitly asked to project fit onto something, # set self as target fit if targetFit is None: targetFit = self projected = False else: projected = True # If fit is calculated and we have nothing to do here, get out # A note on why projected fits don't get to return here. If we return # here, the projection afflictions will not be run as they are # intertwined into the regular fit calculations. So, even if the fit has # been calculated, we need to recalculate it again just to apply the # projections. This is in contract to gang boosts, which are only # calculated once, and their items are then looped and accessed with # self.gangBoosts.iteritems() # We might be able to exit early in the fit calculations if we separate # projections from the normal fit calculations. But we must ensure that # projection have modifying stuff applied, such as gang boosts and other # local modules that may help if self.__calculated and not projected: logger.debug("Fit has already been calculated and is not projected, returning: %r", self) return # Mark fit as calculated self.__calculated = True for runTime in ("early", "normal", "late"): # Items that are unrestricted. These items are run on the local fit # first and then projected onto the target fit it one is designated u = [ (self.character, self.ship), self.drones, self.boosters, self.appliedImplants, self.modules ] # Items that are restricted. These items are only run on the local # fit. They are NOT projected onto the target fit. # See issue 354 r = [(self.mode,), self.projectedDrones, self.projectedModules] # chain unrestricted and restricted into one iterable c = chain.from_iterable(u+r) # We calculate gang bonuses first so that projected fits get them if self.gangBoosts is not None: self.__calculateGangBoosts(runTime) for item in c: # Registering the item about to affect the fit allows us to # track "Affected By" relations correctly if item is not None: # apply effects locally self.register(item) item.calculateModifiedAttributes(self, runTime, False) if projected is True and item not in chain.from_iterable(r): # apply effects onto target fit for _ in xrange(projectionInfo.amount): targetFit.register(item, origin=self) item.calculateModifiedAttributes(targetFit, runTime, True) timer.checkpoint('Done with runtime: %s'%runTime) # Only apply projected fits if fit it not projected itself. if not projected: for fit in self.projectedFits: if fit.getProjectionInfo(self.ID).active: fit.calculateModifiedAttributes(self, withBoosters=withBoosters, dirtyStorage=dirtyStorage) timer.checkpoint('Done with fit calculation') if shadow: logger.debug("Delete shadow fit object") del self
def calculateModifiedAttributes(self, targetFit=None, withBoosters=False, dirtyStorage=None): timer = Timer(u'Fit: {}, {}'.format(self.ID, self.name), logger) logger.debug("Starting fit calculation on: %r, withBoosters: %s", self, withBoosters) shadow = False if targetFit: logger.debug("Applying projections to target: %r", targetFit) projectionInfo = self.getProjectionInfo(targetFit.ID) logger.debug("ProjectionInfo: %s", projectionInfo) if self == targetFit: copied = self # original fit shadow = True self = copy.deepcopy(self) self.fleet = copied.fleet logger.debug( "Handling self projection - making shadow copy of fit. %r => %r", copied, self) # we delete the fit because when we copy a fit, flush() is # called to properly handle projection updates. However, we do # not want to save this fit to the database, so simply remove it eos.db.saveddata_session.delete(self) if self.fleet is not None and withBoosters is True: logger.debug("Fleet is set, gathering gang boosts") self.gangBoosts = self.fleet.recalculateLinear( withBoosters=withBoosters) timer.checkpoint("Done calculating gang boosts for %r" % self) elif self.fleet is None: self.gangBoosts = None # If we're not explicitly asked to project fit onto something, # set self as target fit if targetFit is None: targetFit = self projected = False else: projected = True # If fit is calculated and we have nothing to do here, get out # A note on why projected fits don't get to return here. If we return # here, the projection afflictions will not be run as they are # intertwined into the regular fit calculations. So, even if the fit has # been calculated, we need to recalculate it again just to apply the # projections. This is in contract to gang boosts, which are only # calculated once, and their items are then looped and accessed with # self.gangBoosts.iteritems() # We might be able to exit early in the fit calculations if we separate # projections from the normal fit calculations. But we must ensure that # projection have modifying stuff applied, such as gang boosts and other # local modules that may help if self.__calculated and not projected: logger.debug( "Fit has already been calculated and is not projected, returning: %r", self) return for runTime in ("early", "normal", "late"): # Items that are unrestricted. These items are run on the local fit # first and then projected onto the target fit it one is designated u = [(self.character, self.ship), self.drones, self.fighters, self.boosters, self.appliedImplants, self.modules] # Items that are restricted. These items are only run on the local # fit. They are NOT projected onto the target fit. # See issue 354 r = [(self.mode, ), self.projectedDrones, self.projectedFighters, self.projectedModules] # chain unrestricted and restricted into one iterable c = chain.from_iterable(u + r) # We calculate gang bonuses first so that projected fits get them if self.gangBoosts is not None: self.__calculateGangBoosts(runTime) for item in c: # Registering the item about to affect the fit allows us to # track "Affected By" relations correctly if item is not None: if not self.__calculated: # apply effects locally if this is first time running them on fit self.register(item) item.calculateModifiedAttributes(self, runTime, False) if projected is True and item not in chain.from_iterable( r): # apply effects onto target fit for _ in xrange(projectionInfo.amount): targetFit.register(item, origin=self) item.calculateModifiedAttributes( targetFit, runTime, True) timer.checkpoint('Done with runtime: %s' % runTime) # Mark fit as calculated self.__calculated = True # Only apply projected fits if fit it not projected itself. if not projected: for fit in self.projectedFits: if fit.getProjectionInfo(self.ID).active: fit.calculateModifiedAttributes(self, withBoosters=withBoosters, dirtyStorage=dirtyStorage) timer.checkpoint('Done with fit calculation') if shadow: logger.debug("Delete shadow fit object") del self