Files
pyfa/service/market.py
2013-08-24 01:03:20 +04:00

746 lines
32 KiB
Python

#===============================================================================
# Copyright (C) 2010 Diego Duclos
#
# 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 <http://www.gnu.org/licenses/>.
#===============================================================================
import re
import threading
import wx
import Queue
import eos.db
import eos.types
from service.settings import SettingsProvider, ProxySettings
try:
from collections import OrderedDict
except ImportError:
from gui.utils.compat import OrderedDict
# Event which tells threads dependent on Market that it's initialized
mktRdy = threading.Event()
class ShipBrowserWorkerThread(threading.Thread):
def run(self):
self.queue = Queue.Queue()
self.cache = {}
# Wait for full market initialization (otherwise there's high risky
# this thread will attempt to init Market which is already being inited)
mktRdy.wait(5)
self.processRequests()
def processRequests(self):
queue = self.queue
cache = self.cache
sMarket = Market.getInstance()
while True:
try:
callback, id = queue.get()
set = cache.get(id)
if set is None:
set = sMarket.getShipList(id)
cache[id] = set
wx.CallAfter(callback, (id, set))
except:
pass
finally:
try:
queue.task_done()
except:
pass
class PriceWorkerThread(threading.Thread):
def run(self):
self.queue = Queue.Queue()
self.processUpdates()
def processUpdates(self):
queue = self.queue
while True:
# Grab our data
callback, requests = queue.get()
# Grab prices, this is the time-consuming part
if len(requests) > 0:
proxy = ProxySettings.getInstance().getProxySettings()
if proxy is not None:
proxy = "{0}:{1}".format(*proxy)
eos.types.Price.fetchPrices(requests, proxy=proxy)
wx.CallAfter(callback)
queue.task_done()
def trigger(self, prices, callbacks):
self.queue.put((callbacks, prices))
class SearchWorkerThread(threading.Thread):
def run(self):
self.cv = threading.Condition()
self.searchRequest = None
self.processSearches()
def processSearches(self):
cv = self.cv
while True:
cv.acquire()
while self.searchRequest is None:
cv.wait()
request, callback = self.searchRequest
self.searchRequest = None
cv.release()
sMarket = Market.getInstance()
# Rely on category data provided by eos as we don't hardcode them much in service
filter = eos.types.Category.name.in_(sMarket.SEARCH_CATEGORIES)
results = eos.db.searchItems(request, where=filter,
join=(eos.types.Item.group, eos.types.Group.category),
eager=("icon", "group.category", "metaGroup", "metaGroup.parent"))
items = set()
# Return only published items, consult with Market service this time
for item in results:
if sMarket.getPublicityByItem(item):
items.add(item)
wx.CallAfter(callback, items)
def scheduleSearch(self, text, callback):
self.cv.acquire()
self.searchRequest = (text, callback)
self.cv.notify()
self.cv.release()
class Market():
instance = None
def __init__(self):
self.priceCache = {}
#Init recently used module storage
serviceMarketRecentlyUsedModules = {"pyfaMarketRecentlyUsedModules": []}
self.serviceMarketRecentlyUsedModules = SettingsProvider.getInstance().getSettings("pyfaMarketRecentlyUsedModules", serviceMarketRecentlyUsedModules)
# Start price fetcher
self.priceWorkerThread = PriceWorkerThread()
self.priceWorkerThread.daemon = True
self.priceWorkerThread.start()
# Thread which handles search
self.searchWorkerThread = SearchWorkerThread()
self.searchWorkerThread.daemon = True
self.searchWorkerThread.start()
# Ship browser helper thread
self.shipBrowserWorkerThread = ShipBrowserWorkerThread()
self.shipBrowserWorkerThread.daemon = True
self.shipBrowserWorkerThread.start()
# Items' group overrides
self.customGroups = set()
# Limited edition ships
self.les_grp = eos.types.Group()
self.les_grp.ID = -1
self.les_grp.name = "Limited Issue Ships"
self.les_grp.published = True
ships = self.getCategory("Ship")
self.les_grp.category = ships
self.les_grp.categoryID = ships.ID
self.les_grp.description = ""
self.les_grp.icon = None
self.ITEMS_FORCEGROUP = {
"Opux Luxury Yacht": self.les_grp, # One of those is wedding present at CCP fanfest, another was hijacked from ISD guy during an event
"Silver Magnate": self.les_grp, # Amarr Championship prize
"Gold Magnate": self.les_grp, # Amarr Championship prize
"Armageddon Imperial Issue": self.les_grp, # Amarr Championship prize
"Apocalypse Imperial Issue": self.les_grp, # Amarr Championship prize
"Guardian-Vexor": self.les_grp, # Illegal rewards for the Gallente Frontier Tour Lines event arc
"Megathron Federate Issue": self.les_grp, # Reward during Crielere event
"Raven State Issue": self.les_grp, # AT4 prize
"Tempest Tribal Issue": self.les_grp, # AT4 prize
"Apotheosis": self.les_grp, # 5th EVE anniversary present
"Zephyr": self.les_grp, # 2010 new year gift
"Primae": self.les_grp, # Promotion of planetary interaction
"Freki": self.les_grp, # AT7 prize
"Mimir": self.les_grp, # AT7 prize
"Utu": self.les_grp, # AT8 prize
"Adrestia": self.les_grp, # AT8 prize
"Echelon": self.les_grp, # 2011 new year gift
"Malice": self.les_grp, # AT9 prize
"Vangel": self.les_grp, # AT9 prize
"Cambion": self.les_grp, # AT10 prize
"Etana": self.les_grp, # AT10 prize
"Chremoas": self.les_grp, # AT11 prize :(
"Moracha": self.les_grp } # AT11 prize
self.ITEMS_FORCEGROUP_R = self.__makeRevDict(self.ITEMS_FORCEGROUP)
self.les_grp.addItems = list(self.getItem(itmn) for itmn in self.ITEMS_FORCEGROUP_R[self.les_grp])
self.customGroups.add(self.les_grp)
# List of items which are forcibly published or hidden
self.ITEMS_FORCEPUBLISHED = {
"Data Subverter I": False, # Not used in EVE, probably will appear with Dust link
"Ghost Heavy Missile": False, # Missile used by Sansha
"QA Cross Protocol Analyzer": False, # QA modules used by CCP internally
"QA Damage Module": False,
"QA ECCM": False,
"QA Immunity Module": False,
"QA Multiship Module - 10 Players": False,
"QA Multiship Module - 20 Players": False,
"QA Multiship Module - 40 Players": False,
"QA Multiship Module - 5 Players": False,
"QA Remote Armor Repair System - 5 Players": False,
"QA Shield Transporter - 5 Players": False,
"Aliastra Catalyst": False, # Vanity
"Inner Zone Shipping Catalyst": False, # Vanity
"Intaki Syndicate Catalyst": False, # Vanity
"InterBus Catalyst": False, # Vanity
"Quafe Catalyst": False, # Vanity
"Nefantar Thrasher": False, # Vanity
"Sarum Magnate": False, # Vanity
"Sukuuvestaa Heron": False, # Vanity
"Inner Zone Shipping Imicus": False, # Vanity
"Vherokior Probe": False, # Vanity
"Miasmos Quafe Ultra Edition": False, # Vanity
"Miasmos Quafe Ultramarine Edition": False, # Vanity
"Miasmos Amastris Edition": False, # Vanity
"Goru's Shuttle": False, # Vanity
"Guristas Shuttle": False, # Vanity
"Tash-Murkon Magnate": False, # Vanity
"Scorpion Ishukone Watch": False } # Vanity
# List of groups which are forcibly published
self.GROUPS_FORCEPUBLISHED = {
"Prototype Exploration Ship": False } # We moved the only ship from this group to other group anyway
# Dictionary of items with forced meta groups, uses following format:
# Item name: (metagroup name, parent type name)
self.ITEMS_FORCEDMETAGROUP = {
"'Habitat' Miner I": ("Storyline", "Miner I"),
"'Wild' Miner I": ("Storyline", "Miner I"),
"Medium Nano Armor Repair Unit I": ("Tech I", "Medium Armor Repairer I"),
"Large 'Reprieve' Vestment Reconstructer I": ("Storyline", "Large Armor Repairer I"),
"Khanid Navy Torpedo Launcher": ("Faction", "Torpedo Launcher I"),
"Dark Blood Tracking Disruptor": ("Faction", "Tracking Disruptor I"),
"True Sansha Tracking Disruptor": ("Faction", "Tracking Disruptor I"),
"Shadow Serpentis Remote Sensor Dampener": ("Faction", "Remote Sensor Dampener I") }
# Parent type name: set(item names)
self.ITEMS_FORCEDMETAGROUP_R = {}
for item, value in self.ITEMS_FORCEDMETAGROUP.items():
parent = value[1]
if not parent in self.ITEMS_FORCEDMETAGROUP_R:
self.ITEMS_FORCEDMETAGROUP_R[parent] = set()
self.ITEMS_FORCEDMETAGROUP_R[parent].add(item)
# Dictionary of items with forced market group (service assumes they have no
# market group assigned in db, otherwise they'll appear in both original and forced groups)
self.ITEMS_FORCEDMARKETGROUP = {
"'Alpha' Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
"'Codex' Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
"'Daemon' Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
"'Libram' Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
"Advanced Cerebral Accelerator": 977, # Implants & Boosters > Booster
"Civilian Damage Control": 760, # Ship Equipment > Civilian Modules
"Civilian EM Ward Field": 760, # Ship Equipment > Civilian Modules
"Civilian Explosive Deflection Field": 760, # Ship Equipment > Civilian Modules
"Civilian Hobgoblin": 837, # Drones > Combat Drones > Light Scout Drones
"Civilian Kinetic Deflection Field": 760, # Ship Equipment > Civilian Modules
"Civilian Light Missile Launcher": 760, # Ship Equipment > Civilian Modules
"Civilian Scourge Light Missile": 920, # Ammunition & Charges > Missiles > Light Missiles > Standard Light Missiles
"Civilian Small Remote Armor Repairer": 760, # Ship Equipment > Civilian Modules
"Civilian Small Remote Shield Booster": 760, # Ship Equipment > Civilian Modules
"Civilian Stasis Webifier": 760, # Ship Equipment > Civilian Modules
"Civilian Thermic Dissipation Field": 760, # Ship Equipment > Civilian Modules
"Civilian Warp Disruptor": 760, # Ship Equipment > Civilian Modules
"Hardwiring - Zainou 'Sharpshooter' ZMX10": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
"Hardwiring - Zainou 'Sharpshooter' ZMX100": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
"Hardwiring - Zainou 'Sharpshooter' ZMX1000": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
"Hardwiring - Zainou 'Sharpshooter' ZMX11": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
"Hardwiring - Zainou 'Sharpshooter' ZMX110": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
"Hardwiring - Zainou 'Sharpshooter' ZMX1100": 1493, # Implants & Boosters > Implants > Skill Hardwiring > Missile Implants > Implant Slot 06
"Nugoehuvi Synth Blue Pill Booster": 977, # Implants & Boosters > Booster
"Prototype Cerebral Accelerator": 977, # Implants & Boosters > Booster
"Prototype Iris Probe Launcher": 712, # Ship Equipment > Turrets & Bays > Scan Probe Launchers
"Shadow": 1310, # Drones > Combat Drones > Fighter Bombers
"Sleeper Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
"Standard Cerebral Accelerator": 977, # Implants & Boosters > Booster
"Talocan Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
"Terran Data Analyzer I": 714, # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
"Tetrimon Data Analyzer I": 714 } # Ship Equipment > Electronics and Sensor Upgrades > Scanners > Data and Composition Scanners
self.ITEMS_FORCEDMARKETGROUP_R = self.__makeRevDict(self.ITEMS_FORCEDMARKETGROUP)
# Misc definitions
# 0 is for items w/o meta group
self.META_MAP = OrderedDict([("normal", frozenset((0, 1, 2, 14))),
("faction", frozenset((4, 3))),
("complex", frozenset((6,))),
("officer", frozenset((5,)))])
self.SEARCH_CATEGORIES = ("Drone", "Module", "Subsystem", "Charge", "Implant")
self.ROOT_MARKET_GROUPS = (9, # Modules
1111, # Rigs
157, # Drones
11, # Ammo
1112, # Subsystems
24) # Implants & Boosters
# Tell other threads that Market is at their service
mktRdy.set()
@classmethod
def getInstance(cls):
if cls.instance == None:
cls.instance = Market()
return cls.instance
def __makeRevDict(self, orig):
"""Creates reverse dictionary"""
rev = {}
for item, value in orig.items():
if not value in rev:
rev[value] = set()
rev[value].add(item)
return rev
def getItem(self, identity, *args, **kwargs):
"""Get item by its ID or name"""
if isinstance(identity, eos.types.Item):
item = identity
elif isinstance(identity, (int, basestring)):
item = eos.db.getItem(identity, *args, **kwargs)
elif isinstance(identity, float):
id = int(identity)
item = eos.db.getItem(id, *args, **kwargs)
else:
raise TypeError("Need Item object, integer, float or string as argument")
return item
def getGroup(self, identity, *args, **kwargs):
"""Get group by its ID or name"""
if isinstance(identity, eos.types.Group):
return identity
elif isinstance(identity, (int, float, basestring)):
if isinstance(identity, float):
identity = int(identity)
# Check custom groups
for cgrp in self.customGroups:
# During first comparison we need exact int, not float for matching
if cgrp.ID == identity or cgrp.name == identity:
# Return first match
return cgrp
# Return eos group if everything else returned nothing
return eos.db.getGroup(identity, *args, **kwargs)
else:
raise TypeError("Need Group object, integer, float or string as argument")
def getCategory(self, identity, *args, **kwargs):
"""Get category by its ID or name"""
if isinstance(identity, eos.types.Category):
category = identity
elif isinstance(identity, (int, basestring)):
category = eos.db.getCategory(identity, *args, **kwargs)
elif isinstance(identity, float):
id = int(identity)
category = eos.db.getCategory(id, *args, **kwargs)
else:
raise TypeError("Need Category object, integer, float or string as argument")
return category
def getMetaGroup(self, identity, *args, **kwargs):
"""Get meta group by its ID or name"""
if isinstance(identity, eos.types.MetaGroup):
metaGroup = identity
elif isinstance(identity, (int, basestring)):
metaGroup = eos.db.getMetaGroup(identity, *args, **kwargs)
elif isinstance(identity, float):
id = int(identity)
metaGroup = eos.db.getMetaGroup(id, *args, **kwargs)
else:
raise TypeError("Need MetaGroup object, integer, float or string as argument")
return metaGroup
def getMarketGroup(self, identity, *args, **kwargs):
"""Get market group by its ID"""
if isinstance(identity, eos.types.MarketGroup):
marketGroup = identity
elif isinstance(identity, (int, float)):
id = int(identity)
marketGroup = eos.db.getMarketGroup(id, *args, **kwargs)
else:
raise TypeError("Need MarketGroup object, integer or float as argument")
return marketGroup
def getGroupByItem(self, item):
"""Get group by item"""
if item.name in self.ITEMS_FORCEGROUP:
group = self.ITEMS_FORCEGROUP[item.name]
else:
group = item.group
return group
def getCategoryByItem(self, item):
"""Get category by item"""
grp = self.getGroupByItem(item)
cat = grp.category
return cat
def getMetaGroupByItem(self, item):
"""Get meta group by item"""
# Check if item is in forced metagroup map
if item.name in self.ITEMS_FORCEDMETAGROUP:
# Create meta group from scratch
metaGroup = eos.types.MetaType()
# Get meta group info object based on meta group name
metaGroupInfo = self.getMetaGroup(self.ITEMS_FORCEDMETAGROUP[item.name][0])
# Get parent item based on its name
parent = self.getItem(self.ITEMS_FORCEDMETAGROUP[item.name][1])
# Assign all required for metaGroup variables
metaGroup.info = metaGroupInfo
metaGroup.items = item
metaGroup.parent = parent
metaGroup.metaGroupID = metaGroupInfo.ID
metaGroup.parentTypeID = parent.ID
metaGroup.typeID = item.ID
# If no forced meta group is provided, try to use item's
# meta group if any
else:
metaGroup = item.metaGroup
return metaGroup
def getMetaGroupIdByItem(self, item, fallback=0):
"""Get meta group ID by item"""
id = getattr(self.getMetaGroupByItem(item), "ID", fallback)
return id
def getMarketGroupByItem(self, item, parentcheck=True):
"""Get market group by item, its ID or name"""
# Check if we force market group for given item
if item.name in self.ITEMS_FORCEDMARKETGROUP:
mgid = self.ITEMS_FORCEDMARKETGROUP[item.name]
return self.getMarketGroup(mgid)
# Check if item itself has market group
elif item.marketGroupID:
return item.marketGroup
elif parentcheck:
# If item doesn't have marketgroup, check if it has parent
# item and use its market group
parent = self.getParentItemByItem(item, selfparent=False)
if parent:
return parent.marketGroup
else:
return None
else:
return None
def getParentItemByItem(self, item, selfparent=True):
"""Get parent item by item"""
mg = self.getMetaGroupByItem(item)
if mg:
parent = mg.parent
# Consider self as parent if item has no parent in database
elif selfparent is True:
parent = item
else:
parent = None
return parent
def getVariationsByItems(self, items, alreadyparent=False):
"""Get item variations by item, its ID or name"""
# Set for IDs of parent items
parents = set()
# Set-container for variables
variations = set()
for item in items:
# Get parent item
if alreadyparent is False:
parent = self.getParentItemByItem(item)
else:
parent = item
# Combine both in the same set
parents.add(parent)
# Check for overrides and add them if any
if parent.name in self.ITEMS_FORCEDMETAGROUP_R:
for itmn in self.ITEMS_FORCEDMETAGROUP_R[parent.name]:
variations.add(self.getItem(itmn))
# Add all parents to variations set
variations.update(parents)
# Add all variations of parents to the set
parentids = tuple(item.ID for item in parents)
variations.update(eos.db.getVariations(parentids))
return variations
def getGroupsByCategory(self, cat):
"""Get groups from given category"""
groups = set(filter(lambda grp: self.getPublicityByGroup(grp), cat.groups))
return groups
def getMarketGroupChildren(self, mg):
"""Get the children marketGroups of marketGroup."""
children = set()
for child in mg.children:
children.add(child)
return children
def getItemsByGroup(self, group):
"""Get items assigned to group"""
# Return only public items; also, filter out items
# which were forcibly set to other groups
groupItems = set(group.items)
if hasattr(group, 'addItems'):
groupItems.update(group.addItems)
items = set(filter(lambda item: self.getPublicityByItem(item) and self.getGroupByItem(item) == group, groupItems))
return items
def getItemsByMarketGroup(self, mg, vars=True):
"""Get items in the given market group"""
result = set()
# Get items from eos market group
baseitms = set(mg.items)
# Add hardcoded items to set
if mg.ID in self.ITEMS_FORCEDMARKETGROUP_R:
forceditms = set(self.getItem(itmn) for itmn in self.ITEMS_FORCEDMARKETGROUP_R[mg.ID])
baseitms.update(forceditms)
if vars:
parents = set()
for item in baseitms:
# Add one of the base market group items to result
result.add(item)
parent = self.getParentItemByItem(item, selfparent=False)
# If item has no parent, it's base item (or at least should be)
if parent is None:
parents.add(item)
# Fetch variations only for parent items
variations = self.getVariationsByItems(parents, alreadyparent=True)
for variation in variations:
# Exclude items with their own explicitly defined market groups
if self.getMarketGroupByItem(variation, parentcheck=False) is None:
result.add(variation)
else:
result = baseitms
# Get rid of unpublished items
result = set(filter(lambda item: self.getPublicityByItem(item), result))
return result
def marketGroupHasTypesCheck(self, mg):
"""If market group has any items, return true"""
if mg and mg.ID in self.ITEMS_FORCEDMARKETGROUP_R:
return True
elif len(mg.items) > 0:
return True
else:
return False
def marketGroupValidityCheck(self, mg):
"""Check market group validity"""
# The only known case when group can be invalid is
# when it's declared to have types, but it doesn't contain anything
if mg.hasTypes and not self.marketGroupHasTypesCheck(mg):
return False
else:
return True
def getIconByMarketGroup(self, mg):
"""Return icon associated to marketgroup"""
if mg.icon:
return mg.icon.iconFile
else:
while mg and not mg.hasTypes:
mg = mg.parent
if not mg:
return ""
elif self.marketGroupHasTypesCheck(mg):
# Do not request variations to make process faster
# Pick random item and use its icon
items = self.getItemsByMarketGroup(mg, vars=False)
try:
item = items.pop()
except KeyError:
return ""
return item.icon.iconFile if item.icon else ""
elif self.getMarketGroupChildren(mg) > 0:
kids = self.getMarketGroupChildren(mg)
mktGroups = self.getIconByMarketGroup(kids)
size = len(mktGroups)
return mktGroups.pop() if size > 0 else ""
else:
return ""
def getPublicityByItem(self, item):
"""Return if an item is published"""
if item.name in self.ITEMS_FORCEPUBLISHED:
pub = self.ITEMS_FORCEPUBLISHED[item.name]
else:
pub = item.published
return pub
def getPublicityByGroup(self, group):
"""Return if an group is published"""
if group.name in self.GROUPS_FORCEPUBLISHED:
pub = self.GROUPS_FORCEPUBLISHED[group.name]
else:
pub = group.published
return pub
def getMarketRoot(self):
"""
Get the root of the market tree.
Returns a list, where each element is a tuple containing:
the ID, the name and the icon of the group
"""
root = set()
for id in self.ROOT_MARKET_GROUPS:
mg = self.getMarketGroup(id, eager="icon")
root.add(mg)
return root
def getShipRoot(self):
cat = self.getCategory("Ship")
root = set(self.getGroupsByCategory(cat))
return root
def getShipList(self, grpid):
"""Get ships for given group id"""
grp = self.getGroup(grpid, eager=("items", "items.group", "items.marketGroup"))
ships = self.getItemsByGroup(grp)
for ship in ships:
ship.race
return ships
def getShipListDelayed(self, id, callback):
"""Background version of getShipList"""
self.shipBrowserWorkerThread.queue.put((id, callback))
def searchShips(self, name):
"""Find ships according to given text pattern"""
results = eos.db.searchItems(name)
ships = set()
for item in results:
if self.getCategoryByItem(item).name == "Ship" and self.getPublicityByItem(item):
ships.add(item)
return ships
def searchItems(self, name, callback):
"""Find items according to given text pattern"""
self.searchWorkerThread.scheduleSearch(name, callback)
def directAttrRequest(self, items, attribs):
try:
itemIDs = tuple(map(lambda i: i.ID, items))
except TypeError:
itemIDs = (items.ID,)
try:
attrIDs = tuple(map(lambda i: i.ID, attribs))
except TypeError:
attrIDs = (attribs.ID,)
info = {}
for itemID, typeID, val in eos.db.directAttributeRequest(itemIDs, attrIDs):
info[itemID] = val
return info
def getImplantTree(self):
"""Return implant market group children"""
img = self.getMarketGroup(27)
return self.getMarketGroupChildren(img)
def filterItemsByMeta(self, items, metas):
"""Filter items by meta lvl"""
filtered = set(filter(lambda item: self.getMetaGroupIdByItem(item) in metas, items))
return filtered
def getPriceNow(self, typeID):
"""Get price for provided typeID"""
price = self.priceCache.get(typeID)
if price is None:
price = eos.db.getPrice(typeID)
if price is None:
price = eos.types.Price(typeID)
eos.db.add(price)
self.priceCache[typeID] = price
return price
def getPricesNow(self, typeIDs):
"""Return map of calls to get price against list of typeIDs"""
return map(self.getPrice, typeIDs)
def getPrices(self, typeIDs, callback):
"""Get prices for multiple typeIDs"""
requests = []
for typeID in typeIDs:
price = self.getPriceNow(typeID)
requests.append(price)
def cb():
try:
callback(requests)
except:
pass
eos.db.commit()
self.priceWorkerThread.trigger(requests, cb)
def getSystemWideEffects(self):
"""
Get dictionary with system-wide effects
"""
# Container for system-wide effects
effects = {}
# Expressions for matching when detecting effects we're looking for
validgroups = ("Black Hole Effect Beacon",
"Cataclysmic Variable Effect Beacon",
"Magnetar Effect Beacon",
"Pulsar Effect Beacon",
"Red Giant Beacon",
"Wolf Rayet Effect Beacon",
"Incursion ship attributes effects")
# Stuff we don't want to see in names
garbages = ("Effect", "Beacon", "ship attributes effects")
# Get group with all the system-wide beacons
grp = self.getGroup("Effect Beacon")
beacons = self.getItemsByGroup(grp)
# Cycle through them
for beacon in beacons:
# Check if it belongs to any valid group
for group in validgroups:
# Check beginning of the name only
if re.match(group, beacon.name):
# Get full beacon name
beaconname = beacon.name
for garbage in garbages:
beaconname = re.sub(garbage, "", beaconname)
beaconname = re.sub(" {2,}", " ", beaconname).strip()
# Get short name
shortname = re.sub(group, "", beacon.name)
for garbage in garbages:
shortname = re.sub(garbage, "", shortname)
shortname = re.sub(" {2,}", " ", shortname).strip()
# Get group name
groupname = group
for garbage in garbages:
groupname = re.sub(garbage, "", groupname)
groupname = re.sub(" {2,}", " ", groupname).strip()
# Add stuff to dictionary
if not groupname in effects:
effects[groupname] = set()
effects[groupname].add((beacon, beaconname, shortname))
# Break loop on 1st result
break
return effects