From c17e03d8d01147635ff81b79b46e3e05a31f9984 Mon Sep 17 00:00:00 2001 From: blitzmann Date: Thu, 9 Jul 2015 17:53:41 -0400 Subject: [PATCH] Fixes critical design issue when it comes to projected fits. Disabled some of the more advanced functionality (projection amount and active) to cope to development. Crash still happens occasionally when adding projected fit for unknown reasons - not 100% reproducable yet --- eos/db/saveddata/fit.py | 39 +++++++++++++++++------------- eos/saveddata/fit.py | 32 ++++++++++++------------ gui/builtinViewColumns/baseName.py | 6 ++++- gui/builtinViewColumns/state.py | 10 ++++++-- service/fit.py | 16 ++++++------ 5 files changed, 61 insertions(+), 42 deletions(-) diff --git a/eos/db/saveddata/fit.py b/eos/db/saveddata/fit.py index 4c03bdd32..6b4e44fb4 100644 --- a/eos/db/saveddata/fit.py +++ b/eos/db/saveddata/fit.py @@ -21,6 +21,7 @@ from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.sql import and_ from sqlalchemy.ext.associationproxy import association_proxy +from sqlalchemy.orm.collections import attribute_mapped_collection from eos.db import saveddata_meta from eos.db.saveddata.module import modules_table @@ -51,25 +52,27 @@ projectedFits_table = Table("projectedFits", saveddata_meta, ) class ProjectedFit(object): - def __init__(self, source_item, dest_item, amount=1, active=True): - print "init projected item", source_item, dest_item, active, amount - self.source_item = source_item - self.dest_item = dest_item + def __init__(self, source_fit, k, amount=1, active=True): + print "init projected: ", k, source_fit.name, active, amount + self.sourceID = k + self.source_item = source_fit + self.victim_item = None self.amount = amount self.active = active - self.dest_item.projectionInfo = self + #self.dest_item.setProjectionInfo(self.source_item.ID, self) @reconstructor def init(self): print "db init" - print "\t source:",self.source_item - print "\t dest:", self.dest_item - self.dest_item.projectionInfo = self + print "\t source:", self.source_fit + print "\t dest:", self.victim_fit + #self.dest_item.setProjectionInfo(self.source_item.ID, self) + #print self.dest_item.ship.item.name, ">", self.source_item.ship.item.name,self Fit._Fit__projectedFits = association_proxy( - "projected_items", - "dest_item", - creator=lambda dest_item: ProjectedFit(None, dest_item) + "victimOf", # look at the victimOf association... + "source_fit", # .. and return the source fits + creator=lambda k, victim_fit: ProjectedFit(victim_fit, k) ) mapper(Fit, fits_table, @@ -128,15 +131,17 @@ mapper(Fit, fits_table, backref="fits"), "_Fit__damagePattern": relation(DamagePattern), "_Fit__targetResists": relation(TargetResists), - "dest_items": relationship( + "projectedOnto": relationship( ProjectedFit, - primaryjoin=projectedFits_table.c.victimID == fits_table.c.ID, - backref='dest_item', + primaryjoin=projectedFits_table.c.sourceID == fits_table.c.ID, + backref='source_fit', + collection_class=attribute_mapped_collection('victimID'), cascade='all, delete, delete-orphan'), - "projected_items": relationship( + "victimOf": relationship( ProjectedFit, - primaryjoin=fits_table.c.ID == projectedFits_table.c.sourceID, - backref='source_item', + primaryjoin=fits_table.c.ID == projectedFits_table.c.victimID, + backref='victim_fit', + collection_class=attribute_mapped_collection('sourceID'), cascade='all, delete, delete-orphan'), } ) diff --git a/eos/saveddata/fit.py b/eos/saveddata/fit.py index 391f046b8..9c76dee23 100644 --- a/eos/saveddata/fit.py +++ b/eos/saveddata/fit.py @@ -119,7 +119,7 @@ class Fit(object): self.__capUsed = None self.__capRecharge = None self.__calculatedTargets = [] - self.__projectionInfo = None + self.__projectionMap = {} self.factorReload = False self.fleet = None self.boostsFits = set() @@ -208,15 +208,10 @@ class Fit(object): @property def projectedFits(self): - return self.__projectedFits + return self.__projectedFits.values() - @property - def projectionInfo(self): - return self.__projectionInfo - - @projectionInfo.setter - def projectionInfo(self, projectionInfo): - self.__projectionInfo = projectionInfo + def getProjectionInfo(self, fitID): + return self.projectedOnto.get(fitID, None) @property def projectedDrones(self): @@ -371,7 +366,11 @@ class Fit(object): # If we are in a root ship, add projected fits to clear list # Do not add projected fits if self is already projected - this can # cause infinite recursion in projection loop, eg A > B > C > A - if self.projectionInfo is None: + # @todo: since fits persist, we need to be sure that even if a fit has + # projection info (loaded as a projected fit), this still happens when + # we clear the fit if the fit is the root + #if self.projectionInfo is None: + if True: c = chain(c, self.projectedFits) for stuff in c: @@ -417,10 +416,13 @@ class Fit(object): timer = Timer('Fit: %d, %s'%(self.ID, self.name), logger) logger.debug("Starting fit calculation on: %d %s (%s)" % (self.ID, self.name, self.ship.item.name)) - + #print self.projectedFits if targetFit: - logger.debug("Applying projections to target: %d %s (%s)" % - (targetFit.ID, targetFit.name, targetFit.ship.item.name)) + logger.debug("Applying projections to target: %d %s (%s)", + targetFit.ID, targetFit.name, targetFit.ship.item.name) + projectionInfo = self.getProjectionInfo(targetFit.ID) + logger.debug("ProjectionInfo: amount=%s, active=%s, instance=%s", + projectionInfo.amount, projectionInfo.active, projectionInfo) refreshBoosts = False if withBoosters is True: @@ -489,7 +491,7 @@ class Fit(object): self.register(item) item.calculateModifiedAttributes(self, runTime, False) if projected is True: - for _ in xrange(self.projectionInfo.amount): + #for _ in xrange(projectionInfo.amount): targetFit.register(item) item.calculateModifiedAttributes(targetFit, runTime, True) @@ -498,7 +500,7 @@ class Fit(object): # Only apply projected fits if fit it not projected itself. if not projected: for fit in self.projectedFits: - if fit.projectionInfo.active: + #if fit.getProjectionInfo(self.ID).active: fit.calculateModifiedAttributes(self, withBoosters=withBoosters, dirtyStorage=dirtyStorage) timer.checkpoint('Done with fit calculation') diff --git a/gui/builtinViewColumns/baseName.py b/gui/builtinViewColumns/baseName.py index 0bd0e8c43..cf9222414 100644 --- a/gui/builtinViewColumns/baseName.py +++ b/gui/builtinViewColumns/baseName.py @@ -21,6 +21,8 @@ from gui import builtinViewColumns from gui.viewColumn import ViewColumn from gui import bitmapLoader +import gui.mainFrame + import wx from eos.types import Drone, Cargo, Fit, Module, Slot, Rack import service @@ -29,6 +31,7 @@ class BaseName(ViewColumn): name = "Base Name" def __init__(self, fittingView, params): ViewColumn.__init__(self, fittingView) + self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.columnText = "Name" self.shipImage = fittingView.imageList.GetImageIndex("ship_small", "icons") self.mask = wx.LIST_MASK_TEXT @@ -39,7 +42,8 @@ class BaseName(ViewColumn): elif isinstance(stuff, Cargo): return "%dx %s" % (stuff.amount, stuff.item.name) elif isinstance(stuff, Fit): - return "%dx %s (%s)" % (stuff.projectionInfo.amount, stuff.name, stuff.ship.item.name) + fitID = self.mainFrame.getActiveFit() + return "%dx %s (%s)" % (stuff.getProjectionInfo(fitID).amount, stuff.name, stuff.ship.item.name) elif isinstance(stuff, Rack): if service.Fit.getInstance().serviceFittingOptions["rackLabels"]: if stuff.slot == Slot.MODE: diff --git a/gui/builtinViewColumns/state.py b/gui/builtinViewColumns/state.py index 0925d2f2d..8110a85ad 100644 --- a/gui/builtinViewColumns/state.py +++ b/gui/builtinViewColumns/state.py @@ -19,6 +19,8 @@ from gui.viewColumn import ViewColumn from gui import bitmapLoader +import gui.mainFrame + import wx from eos.types import Drone, Module, Rack, Fit from eos.types import State as State_ @@ -27,6 +29,7 @@ class State(ViewColumn): name = "State" def __init__(self, fittingView, params): ViewColumn.__init__(self, fittingView) + self.mainFrame = gui.mainFrame.MainFrame.getInstance() self.resizable = False self.size = 16 self.maxsize = self.size @@ -56,9 +59,12 @@ class State(ViewColumn): else: return self.fittingView.imageList.GetImageIndex("state_%s_small" % State_.getName(stuff.state).lower(), "icons") elif isinstance(stuff, Fit): - if stuff.projectionInfo is None: + fitID = self.mainFrame.getActiveFit() + projectionInfo = stuff.getProjectionInfo(fitID) + + if projectionInfo is None: return -1 - if stuff.projectionInfo.active: + if projectionInfo.active: return generic_active return generic_inactive else: diff --git a/service/fit.py b/service/fit.py index dddc4ebfb..9effe43a6 100644 --- a/service/fit.py +++ b/service/fit.py @@ -325,7 +325,8 @@ class Fit(object): if isinstance(thing, eos.types.Fit): if thing.ID == fitID: return - fit.projectedFits.append(thing) + + fit.__projectedFits[thing.ID] = thing elif thing.category.name == "Drone": drone = None for d in fit.projectedDrones.find(thing): @@ -374,10 +375,10 @@ class Fit(object): def changeAmount(self, fitID, projected_fit, amount): """Change amount of projected fits""" fit = eos.db.getFit(fitID) - amount = min(20, max(1, amount)) # 1 <= a <= 5 - - if projected_fit.projectionInfo is not None: - projected_fit.projectionInfo.amount = amount + amount = min(20, max(1, amount)) # 1 <= a <= 20 + projectionInfo = projected_fit.getProjectionInfo(fitID) + if projectionInfo: + projectionInfo.amount = amount eos.db.commit() self.recalc(fit) @@ -389,7 +390,8 @@ class Fit(object): elif isinstance(thing, eos.types.Module): fit.projectedModules.remove(thing) else: - fit.projectedFits.remove(thing) + del fit.__projectedFits[thing.ID] + #fit.projectedFits.remove(thing) eos.db.commit() self.recalc(fit) @@ -937,7 +939,7 @@ class Fit(object): self.recalc(fit) def recalc(self, fit, withBoosters=False): - logger.debug("="*10+"recalc"+"="*10) + logger.debug("="*10+"recalc"+"="*10) if fit.factorReload is not self.serviceFittingOptions["useGlobalForceReload"]: fit.factorReload = self.serviceFittingOptions["useGlobalForceReload"] fit.clear()