Get rid of idea of "better" replacements
It turned out to be maintenance hell and it's just hard to find all the dual-action attributes (like crash vs GD sig attr, AB cycle time modification vs rep cycle time modification etc)
This commit is contained in:
@@ -41,8 +41,7 @@ items_table = Table("invtypes", gamedata_meta,
|
||||
Column("iconID", Integer),
|
||||
Column("graphicID", Integer),
|
||||
Column("groupID", Integer, ForeignKey("invgroups.groupID"), index=True),
|
||||
Column("replaceSame", String),
|
||||
Column("replaceBetter", String))
|
||||
Column("replacements", String))
|
||||
|
||||
from .metaGroup import metatypes_table # noqa
|
||||
from .traits import traits_table # noqa
|
||||
|
||||
@@ -984,7 +984,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
charge = self.charge
|
||||
Module.__init__(self, item, self.baseItem, self.mutaplasmid)
|
||||
self.state = state
|
||||
self.charge = charge
|
||||
if self.isValidCharge(charge):
|
||||
self.charge = charge
|
||||
for x in self.mutators.values():
|
||||
Mutator(self, x.attribute, x.value)
|
||||
|
||||
|
||||
@@ -679,7 +679,7 @@ class MainFrame(wx.Frame):
|
||||
if changes:
|
||||
wx.PostEvent(self, GE.FitChanged(fitID=fitID))
|
||||
|
||||
sPrice.optimizeFitPrice(fit, cb, includeBetter=True, fetchTimeout=10)
|
||||
sPrice.optimizeFitPrice(fit, cb, fetchTimeout=10)
|
||||
|
||||
def AdditionsTabSelect(self, event):
|
||||
selTab = self.additionsSelect.index(event.GetId())
|
||||
|
||||
@@ -178,36 +178,15 @@ def main(db, json_path):
|
||||
|
||||
def fillReplacements(tables):
|
||||
|
||||
def compareAttrs(attrs1, attrs2, attrHig):
|
||||
"""
|
||||
Compares received attribute sets. Returns:
|
||||
- 0 if sets have no attributes for comparison
|
||||
- 1 if sets are different
|
||||
- 2 if sets are exactly the same
|
||||
- 3 if first set is strictly better
|
||||
- 4 if second set is strictly better
|
||||
"""
|
||||
def compareAttrs(attrs1, attrs2):
|
||||
# Consider items as different if they have no attrs
|
||||
if len(attrs1) == 0 and len(attrs2) == 0:
|
||||
return 0
|
||||
return False
|
||||
if set(attrs1) != set(attrs2):
|
||||
return 1
|
||||
return False
|
||||
if all(attrs1[aid] == attrs2[aid] for aid in attrs1):
|
||||
return 2
|
||||
if all(
|
||||
(attrs1[aid] <= attrs2[aid] and attrHig[aid] == 0) or
|
||||
(attrs1[aid] >= attrs2[aid] and attrHig[aid] == 1) or
|
||||
(attrs1[aid] == attrs2[aid] and attrHig[aid] == 2)
|
||||
for aid in attrs1
|
||||
):
|
||||
return 3
|
||||
if all(
|
||||
(attrs2[aid] <= attrs1[aid] and attrHig[aid] == 0) or
|
||||
(attrs2[aid] >= attrs1[aid] and attrHig[aid] == 1) or
|
||||
(attrs2[aid] == attrs1[aid] and attrHig[aid] == 2)
|
||||
for aid in attrs1
|
||||
):
|
||||
return 4
|
||||
return 1
|
||||
return True
|
||||
return False
|
||||
|
||||
print('finding replacements')
|
||||
skillReqAttribs = {
|
||||
@@ -240,13 +219,15 @@ def main(db, json_path):
|
||||
# Ignore these attributes for comparison purposes
|
||||
elif attributeID in (
|
||||
# We do not need mass as it affects final ship stats only when carried by ship itself
|
||||
# (and we're not going to replace ships), but it's wildly inconsistent for other items
|
||||
# (and we're not going to replace ships), but it's wildly inconsistent for other items,
|
||||
# which otherwise would be the same
|
||||
4, # mass
|
||||
124, # mainColor
|
||||
162, # radius
|
||||
422, # techLevel
|
||||
633, # metaLevel
|
||||
1692 # metaGroupID
|
||||
1692, # metaGroupID
|
||||
1768 # typeColorScheme
|
||||
):
|
||||
continue
|
||||
else:
|
||||
@@ -267,40 +248,6 @@ def main(db, json_path):
|
||||
except (KeyError, ValueError):
|
||||
continue
|
||||
typeSkillReqs[skillType] = skillLevel
|
||||
# Get data on attribute highIsGood flag
|
||||
# Format: {type ID: 0 if high is bad, 1 if high is good, 2 if neither}
|
||||
attrHig = {}
|
||||
for row in tables['dgmattribs']:
|
||||
attrHig[row['attributeID']] = 1 if row['highIsGood'] else 0
|
||||
# As CCP data is not really consistent, do some overrides
|
||||
attrHig[4] = 0 # mass
|
||||
# Sometimes high is positive, sometimes it's not (e.g. AB cycle bonus vs smartbomb cycle bonus)
|
||||
attrHig[66] = 2 # durationBonus
|
||||
# Sometimes high is positive, sometimes it's not (e.g. invuln cycle vs rep cycle)
|
||||
attrHig[73] = 2 # duration
|
||||
attrHig[151] = 0 # agilityBonus
|
||||
attrHig[161] = 0 # volume
|
||||
attrHig[293] = 0 # rofBonus
|
||||
attrHig[310] = 0 # cpuNeedBonus
|
||||
attrHig[312] = 0 # durationSkillBonus
|
||||
attrHig[314] = 0 # capRechargeBonus
|
||||
attrHig[317] = 0 # capNeedBonus
|
||||
attrHig[319] = 0 # warpCapacitorNeedBonus
|
||||
attrHig[323] = 0 # powerNeedBonus
|
||||
attrHig[331] = 2 # implantness
|
||||
attrHig[338] = 0 # rechargeratebonus
|
||||
attrHig[440] = 0 # manufacturingTimeBonus
|
||||
attrHig[441] = 0 # turretSpeeBonus
|
||||
attrHig[452] = 0 # copySpeedBonus
|
||||
attrHig[453] = 0 # blueprintmanufactureTimeBonus
|
||||
attrHig[468] = 0 # mineralNeedResearchBonus
|
||||
attrHig[780] = 0 # iceHarvestCycleBonus
|
||||
attrHig[848] = 0 # aoeCloudSizeBonus
|
||||
attrHig[927] = 0 # miningUpgradeCPUReductionBonus
|
||||
attrHig[1087] = 2 # boosterness
|
||||
attrHig[1125] = 0 # boosterChanceBonus
|
||||
attrHig[1126] = 0 # boosterAttributeModifier
|
||||
attrHig[1156] = 0 # maxScanDeviationModifier
|
||||
# Format: {group ID: category ID}
|
||||
groupCategories = {}
|
||||
for row in tables['evegroups']:
|
||||
@@ -338,28 +285,17 @@ def main(db, json_path):
|
||||
groupData = groupedData.setdefault((typeGroup, typeSkillreqs, typeEffects), [])
|
||||
groupData.append((typeID, typeAttribs))
|
||||
# Format: {type ID: set(type IDs)}
|
||||
same = {}
|
||||
better = {}
|
||||
# Now, go through composed groups and for every item within it find items which are
|
||||
# the same and which are better
|
||||
replacements = {}
|
||||
# Now, go through composed groups and for every item within it
|
||||
# find items which are the same
|
||||
for groupData in groupedData.values():
|
||||
for type1, type2 in itertools.combinations(groupData, 2):
|
||||
comparisonResult = compareAttrs(type1[1], type2[1], attrHig)
|
||||
# Equal
|
||||
if comparisonResult == 2:
|
||||
same.setdefault(type1[0], set()).add(type2[0])
|
||||
same.setdefault(type2[0], set()).add(type1[0])
|
||||
# First is better
|
||||
elif comparisonResult == 3:
|
||||
better.setdefault(type2[0], set()).add(type1[0])
|
||||
# Second is better
|
||||
elif comparisonResult == 4:
|
||||
better.setdefault(type1[0], set()).add(type2[0])
|
||||
if compareAttrs(type1[1], type2[1]):
|
||||
replacements.setdefault(type1[0], set()).add(type2[0])
|
||||
replacements.setdefault(type2[0], set()).add(type1[0])
|
||||
# Put this data into types table so that normal process hooks it up
|
||||
for row in tables['evetypes']:
|
||||
typeID = row['typeID']
|
||||
row['replaceSame'] = ','.join('{}'.format(tid) for tid in sorted(same.get(typeID, ())))
|
||||
row['replaceBetter'] = ','.join('{}'.format(tid) for tid in sorted(better.get(typeID, ())))
|
||||
row['replacements'] = ','.join('{}'.format(tid) for tid in sorted(replacements.get(row['typeID'], ())))
|
||||
|
||||
data = {}
|
||||
|
||||
|
||||
@@ -796,12 +796,10 @@ class Market(object):
|
||||
filtered = set([item for item in items if self.getMetaGroupIdByItem(item) in metas])
|
||||
return filtered
|
||||
|
||||
def getReplacements(self, identity, includeBetter):
|
||||
def getReplacements(self, identity):
|
||||
item = self.getItem(identity)
|
||||
# We already store needed type IDs in database
|
||||
replTypeIDs = {int(i) for i in item.replaceSame.split(",") if i}
|
||||
if includeBetter:
|
||||
replTypeIDs.update({int(i) for i in item.replaceBetter.split(",") if i})
|
||||
replTypeIDs = {int(i) for i in item.replacements.split(",") if i}
|
||||
if not replTypeIDs:
|
||||
return ()
|
||||
# As replacements were generated without keeping track which items were published,
|
||||
|
||||
@@ -70,15 +70,15 @@ def exportMultiBuy(fit, options, callback):
|
||||
|
||||
if options[Options.OPTIMIZE_PRICES.value]:
|
||||
|
||||
def cb(replacements):
|
||||
def processCheaperMapCb(replacementsCheaper):
|
||||
updatedAmounts = {}
|
||||
for item, itemAmount in itemAmounts.items():
|
||||
_addItem(updatedAmounts, replacements.get(item, item), itemAmount)
|
||||
_addItem(updatedAmounts, replacementsCheaper.get(item, item), itemAmount)
|
||||
string = _prepareString(fit.ship.item, updatedAmounts)
|
||||
callback(string)
|
||||
|
||||
priceSvc = sPrc.getInstance()
|
||||
priceSvc.findCheaperReplacements(itemAmounts, cb, includeBetter=True)
|
||||
priceSvc.findCheaperReplacements(itemAmounts, processCheaperMapCb)
|
||||
else:
|
||||
string = _prepareString(fit.ship.item, itemAmounts)
|
||||
if callback:
|
||||
|
||||
@@ -201,14 +201,14 @@ class Price:
|
||||
pyfalog.debug("Clearing Prices")
|
||||
db.clearPrices()
|
||||
|
||||
def findCheaperReplacements(self, items, callback, includeBetter, fetchTimeout=10):
|
||||
def findCheaperReplacements(self, items, callback, fetchTimeout=10):
|
||||
sMkt = Market.getInstance()
|
||||
|
||||
replacementsAll = {} # All possible item replacements
|
||||
for item in items:
|
||||
if item in replacementsAll:
|
||||
continue
|
||||
itemRepls = sMkt.getReplacements(item, includeBetter)
|
||||
itemRepls = sMkt.getReplacements(item)
|
||||
if itemRepls:
|
||||
replacementsAll[item] = itemRepls
|
||||
itemsToFetch = {i for i in chain(replacementsAll.keys(), *replacementsAll.values())}
|
||||
@@ -230,16 +230,19 @@ class Price:
|
||||
validityOverride = 2 * 60 * 60
|
||||
self.getPrices(itemsToFetch, makeCheapMapCb, fetchTimeout=fetchTimeout, validityOverride=validityOverride)
|
||||
|
||||
def optimizeFitPrice(self, fit, callback, includeBetter, fetchTimeout=10):
|
||||
def optimizeFitPrice(self, fit, callback, fetchTimeout=10):
|
||||
|
||||
def updateFitCb(replacementsCheaper):
|
||||
changes = False
|
||||
for container in (fit.modules, fit.drones, fit.fighters, fit.implants, fit.boosters, fit.cargo):
|
||||
for mod in fit.modules:
|
||||
if mod.item in replacementsCheaper:
|
||||
mod.rebase(replacementsCheaper[mod.item])
|
||||
changes = True
|
||||
if mod.charge in replacementsCheaper:
|
||||
mod.charge = replacementsCheaper[mod.charge]
|
||||
changes = True
|
||||
for container in (fit.drones, fit.fighters, fit.implants, fit.boosters, fit.cargo):
|
||||
for obj in container:
|
||||
charge = getattr(obj, 'charge', None)
|
||||
if charge is not None and charge in replacementsCheaper:
|
||||
obj.charge = replacementsCheaper[charge]
|
||||
changes = True
|
||||
if obj.item in replacementsCheaper:
|
||||
obj.rebase(replacementsCheaper[obj.item])
|
||||
changes = True
|
||||
@@ -252,7 +255,7 @@ class Price:
|
||||
pyfalog.critical(e)
|
||||
|
||||
fitItems = {i for i in self.fitItemIter(fit) if i is not fit.ship.item}
|
||||
self.findCheaperReplacements(fitItems, updateFitCb, includeBetter, fetchTimeout=fetchTimeout)
|
||||
self.findCheaperReplacements(fitItems, updateFitCb, fetchTimeout=fetchTimeout)
|
||||
|
||||
|
||||
class PriceWorkerThread(threading.Thread):
|
||||
|
||||
Reference in New Issue
Block a user