From 083b618b71c36e11fc42af9b7947de76c652c21f Mon Sep 17 00:00:00 2001 From: P Date: Wed, 15 Aug 2018 20:38:05 -0700 Subject: [PATCH 1/8] 1695 fixes + tox test fixes --- service/fit.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/service/fit.py b/service/fit.py index 122de2fa6..51bee531d 100644 --- a/service/fit.py +++ b/service/fit.py @@ -626,12 +626,11 @@ class Fit(object): def changeModule(self, fitID, position, newItemID): fit = eos.db.getFit(fitID) + module = fit.modules[position] # We're trying to add a charge to a slot, which won't work. Instead, try to add the charge to the module in that slot. - if self.isAmmo(newItemID): - module = fit.modules[position] - if not module.isEmpty: - self.setAmmo(fitID, newItemID, [module]) + if self.isAmmo(newItemID) and not module.isEmpty: + self.setAmmo(fitID, newItemID, [module]) return True pyfalog.debug("Changing position of module from position ({0}) for fit ID: {1}", position, fitID) @@ -641,13 +640,17 @@ class Fit(object): # Dummy it out in case the next bit fails fit.modules.toDummy(position) + ret = None try: m = es_Module(item) except ValueError: pyfalog.warning("Invalid item: {0}", newItemID) return False - - if m.fits(fit): + if not module.isEmpty and m.slot != module.slot: + fit.modules.toModule(position, module) + # Fits, but we selected wrong slot type, so don't want to overwrite because we will append on failure (none) + ret = None + elif m.fits(fit): m.owner = fit fit.modules.toModule(position, m) if m.isValidState(State.ACTIVE): @@ -661,9 +664,8 @@ class Fit(object): fit.fill() eos.db.commit() - return True - else: - return None + ret = True + return ret def moveCargoToModule(self, fitID, moduleIdx, cargoIdx, copyMod=False): """ From 6c12e1c5fc86f3eb50331406daeca041600dc0a5 Mon Sep 17 00:00:00 2001 From: P Date: Wed, 15 Aug 2018 22:23:35 -0700 Subject: [PATCH 2/8] fix bug issue 1690 as well --- service/fit.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/service/fit.py b/service/fit.py index 51bee531d..877792d76 100644 --- a/service/fit.py +++ b/service/fit.py @@ -639,14 +639,13 @@ class Fit(object): # Dummy it out in case the next bit fails fit.modules.toDummy(position) - ret = None try: m = es_Module(item) except ValueError: pyfalog.warning("Invalid item: {0}", newItemID) return False - if not module.isEmpty and m.slot != module.slot: + if m.slot != module.slot: fit.modules.toModule(position, module) # Fits, but we selected wrong slot type, so don't want to overwrite because we will append on failure (none) ret = None From 2001a395e5d53fdd4ea8ae3e2b7978564d15d856 Mon Sep 17 00:00:00 2001 From: P Date: Sun, 19 Aug 2018 17:28:24 -0700 Subject: [PATCH 3/8] extra check, swap instead of clone if unique module --- gui/builtinViews/fittingView.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index d6bf4ae0c..b0c993736 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -477,7 +477,7 @@ class FittingView(d.Display): return if getattr(mod2, "modPosition") is not None: - if clone and mod2.isEmpty: + if clone and mod2.isEmpty and mod1.getModifiedItemAttr("maxGroupFitted", None) < 1: sFit.cloneModule(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition) else: sFit.swapModules(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition) From 2f40365a0369f663ddc595c09de0d0c633ef9e70 Mon Sep 17 00:00:00 2001 From: P Date: Sun, 19 Aug 2018 17:42:55 -0700 Subject: [PATCH 4/8] default return of getModifiedAttr so can use comparison --- gui/builtinViews/fittingView.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/builtinViews/fittingView.py b/gui/builtinViews/fittingView.py index b0c993736..458aa4ff2 100644 --- a/gui/builtinViews/fittingView.py +++ b/gui/builtinViews/fittingView.py @@ -477,7 +477,7 @@ class FittingView(d.Display): return if getattr(mod2, "modPosition") is not None: - if clone and mod2.isEmpty and mod1.getModifiedItemAttr("maxGroupFitted", None) < 1: + if clone and mod2.isEmpty and mod1.getModifiedItemAttr("maxGroupFitted", 0) < 1.0: sFit.cloneModule(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition) else: sFit.swapModules(self.mainFrame.getActiveFit(), srcIdx, mod2.modPosition) From b4e765abfa828ea4e85cb62166bf1b01854be833 Mon Sep 17 00:00:00 2001 From: P Date: Mon, 20 Aug 2018 21:41:50 -0700 Subject: [PATCH 5/8] add None checks in deleteFit to prevent exceptions --- service/fit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service/fit.py b/service/fit.py index 122de2fa6..67c0e1edc 100644 --- a/service/fit.py +++ b/service/fit.py @@ -187,11 +187,11 @@ class Fit(object): # error during the command loop refreshFits = set() for projection in list(fit.projectedOnto.values()): - if projection.victim_fit != fit and projection.victim_fit in eos.db.saveddata_session: # GH issue #359 + if projection.victim_fit and projection.victim_fit != fit and projection.victim_fit in eos.db.saveddata_session: # GH issue #359 refreshFits.add(projection.victim_fit) for booster in list(fit.boostedOnto.values()): - if booster.boosted_fit != fit and booster.boosted_fit in eos.db.saveddata_session: # GH issue #359 + if booster.boosted_fit and booster.boosted_fit != fit and booster.boosted_fit in eos.db.saveddata_session: # GH issue #359 refreshFits.add(booster.boosted_fit) eos.db.remove(fit) From ff222b8d6233c502e856658921492943bb8dd4f9 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Tue, 21 Aug 2018 19:39:07 +0300 Subject: [PATCH 6/8] Some fixes to DB conversion script --- scripts/jsonToSql.py | 199 ++++++++++++++++++++----------------------- 1 file changed, 91 insertions(+), 108 deletions(-) diff --git a/scripts/jsonToSql.py b/scripts/jsonToSql.py index 34bab22c0..e4a19e77d 100755 --- a/scripts/jsonToSql.py +++ b/scripts/jsonToSql.py @@ -25,7 +25,7 @@ import re # Add eos root path to sys.path so we can import ourselves path = os.path.dirname(__file__) -sys.path.append(os.path.realpath(os.path.join(path, ".."))) +sys.path.insert(0, os.path.realpath(os.path.join(path, '..'))) import json import argparse @@ -50,66 +50,66 @@ def main(db, json_path): # Config dict tables = { - "clonegrades": eos.gamedata.AlphaCloneSkill, - "dgmattribs": eos.gamedata.AttributeInfo, - "dgmeffects": eos.gamedata.Effect, - "dgmtypeattribs": eos.gamedata.Attribute, - "dgmtypeeffects": eos.gamedata.ItemEffect, - "dgmunits": eos.gamedata.Unit, - "icons": eos.gamedata.Icon, - "evecategories": eos.gamedata.Category, - "evegroups": eos.gamedata.Group, - "invmetagroups": eos.gamedata.MetaGroup, - "invmetatypes": eos.gamedata.MetaType, - "evetypes": eos.gamedata.Item, - "phbtraits": eos.gamedata.Traits, - "phbmetadata": eos.gamedata.MetaData, - "mapbulk_marketGroups": eos.gamedata.MarketGroup, + 'clonegrades': eos.gamedata.AlphaCloneSkill, + 'dgmattribs': eos.gamedata.AttributeInfo, + 'dgmeffects': eos.gamedata.Effect, + 'dgmtypeattribs': eos.gamedata.Attribute, + 'dgmtypeeffects': eos.gamedata.ItemEffect, + 'dgmunits': eos.gamedata.Unit, + 'icons': eos.gamedata.Icon, + 'evecategories': eos.gamedata.Category, + 'evegroups': eos.gamedata.Group, + 'invmetagroups': eos.gamedata.MetaGroup, + 'invmetatypes': eos.gamedata.MetaType, + 'evetypes': eos.gamedata.Item, + 'phbtraits': eos.gamedata.Traits, + 'phbmetadata': eos.gamedata.MetaData, + 'mapbulk_marketGroups': eos.gamedata.MarketGroup, } fieldMapping = { - "dgmattribs": { - "displayName_en-us": "displayName" + 'dgmattribs': { + 'displayName_en-us': 'displayName' }, - "dgmeffects": { - "displayName_en-us": "displayName", - "description_en-us": "description" + 'dgmeffects': { + 'displayName_en-us': 'displayName', + 'description_en-us': 'description' }, - "dgmunits": { - "displayName_en-us": "displayName" + 'dgmunits': { + 'displayName_en-us': 'displayName' }, #icons??? - "evecategories": { - "categoryName_en-us": "categoryName" + 'evecategories': { + 'categoryName_en-us': 'categoryName' }, - "evegroups": { - "groupName_en-us": "groupName" + 'evegroups': { + 'groupName_en-us': 'groupName' }, - "invmetagroups": { - "metaGroupName_en-us": "metaGroupName" + 'invmetagroups': { + 'metaGroupName_en-us': 'metaGroupName' }, - "evetypes": { - "typeName_en-us": "typeName", - "description_en-us": "description" + 'evetypes': { + 'typeName_en-us': 'typeName', + 'description_en-us': 'description' }, #phbtraits??? - "mapbulk_marketGroups": { - "marketGroupName_en-us": "marketGroupName", - "description_en-us": "description" + 'mapbulk_marketGroups': { + 'marketGroupName_en-us': 'marketGroupName', + 'description_en-us': 'description' } } rowsInValues = ( - "evetypes", - "evegroups", - "evecategories" + 'evetypes', + 'evegroups', + 'evecategories' ) def convertIcons(data): new = [] for k, v in list(data.items()): - v["iconID"] = k + v['iconID'] = k new.append(v) return new @@ -123,23 +123,23 @@ def main(db, json_path): check = {} for ID in data: - for skill in data[ID]["skills"]: + for skill in data[ID]['skills']: newData.append({ - "alphaCloneID": int(ID), - "alphaCloneName": "Alpha Clone", - "typeID": skill["typeID"], - "level": skill["level"]}) + 'alphaCloneID': int(ID), + 'alphaCloneName': 'Alpha Clone', + 'typeID': skill['typeID'], + 'level': skill['level']}) if ID not in check: check[ID] = {} - check[ID][int(skill["typeID"])] = int(skill["level"]) + check[ID][int(skill['typeID'])] = int(skill['level']) if not functools.reduce(lambda a, b: a if a == b else False, [v for _, v in check.items()]): - raise Exception("Alpha Clones not all equal") + raise Exception('Alpha Clones not all equal') newData = [x for x in newData if x['alphaCloneID'] == 1] if len(newData) == 0: - raise Exception("Alpha Clone processing failed") + raise Exception('Alpha Clone processing failed') return newData @@ -147,61 +147,44 @@ def main(db, json_path): def convertSection(sectionData): sectionLines = [] - headerText = "{}".format(sectionData["header"]) + headerText = '{}'.format(sectionData['header']) sectionLines.append(headerText) - for bonusData in sectionData["bonuses"]: - prefix = "{} ".format(bonusData["number"]) if "number" in bonusData else "" - bonusText = "{}{}".format(prefix, bonusData["text"].replace("\u00B7", "\u2022 ")) + for bonusData in sectionData['bonuses']: + prefix = '{} '.format(bonusData['number']) if 'number' in bonusData else '' + bonusText = '{}{}'.format(prefix, bonusData['text'].replace('\u00B7', '\u2022 ')) sectionLines.append(bonusText) - sectionLine = "
\n".join(sectionLines) + sectionLine = '
\n'.join(sectionLines) return sectionLine newData = [] for row in data: typeLines = [] - typeId = row["typeID"] - traitData = row["traits"] - for skillData in sorted(traitData.get("skills", ()), key=lambda i: i["header"]): + typeId = row['typeID'] + traitData = row['traits_en-us'] + for skillData in sorted(traitData.get('skills', ()), key=lambda i: i['header']): typeLines.append(convertSection(skillData)) - if "role" in traitData: - typeLines.append(convertSection(traitData["role"])) - if "misc" in traitData: - typeLines.append(convertSection(traitData["misc"])) - traitLine = "
\n
\n".join(typeLines) - newRow = {"typeID": typeId, "traitText": traitLine} + if 'role' in traitData: + typeLines.append(convertSection(traitData['role'])) + if 'misc' in traitData: + typeLines.append(convertSection(traitData['misc'])) + traitLine = '
\n
\n'.join(typeLines) + newRow = {'typeID': typeId, 'traitText': traitLine} newData.append(newRow) return newData - def convertTypes(typesData): - """ - Add factionID column to evetypes table. - """ - factionMap = {} - with open(os.path.join(jsonPath, "fsdTypeOverrides.json")) as f: - overridesData = json.load(f) - for typeID, typeData in list(overridesData.items()): - factionID = typeData.get("factionID") - if factionID is not None: - factionMap[int(typeID)] = factionID - for row in typesData: - row['factionID'] = factionMap.get(int(row['typeID'])) - return typesData - data = {} # Dump all data to memory so we can easely cross check ignored rows for jsonName, cls in tables.items(): - with open(os.path.join(jsonPath, "{}.json".format(jsonName)), encoding="utf-8") as f: + with open(os.path.join(jsonPath, '{}.json'.format(jsonName)), encoding='utf-8') as f: tableData = json.load(f) if jsonName in rowsInValues: tableData = list(tableData.values()) - if jsonName == "icons": + if jsonName == 'icons': tableData = convertIcons(tableData) - if jsonName == "phbtraits": + if jsonName == 'phbtraits': tableData = convertTraits(tableData) - if jsonName == "evetypes": - tableData = convertTypes(tableData) - if jsonName == "clonegrades": + if jsonName == 'clonegrades': tableData = convertClones(tableData) data[jsonName] = tableData @@ -209,23 +192,23 @@ def main(db, json_path): # Sometimes CCP unpublishes some items we want to have published, we # can do it here - just add them to initial set eveTypes = set() - for row in data["evetypes"]: - if (row["published"] + for row in data['evetypes']: + if (row['published'] or row['groupID'] == 1306 # group Ship Modifiers, for items like tactical t3 ship modes - or row['typeName'].startswith('Civilian') # Civilian weapons + or row['typeName_en-us'].startswith('Civilian') # Civilian weapons or row['typeID'] in (41549, 41548, 41551, 41550) # Micro Bombs (Fighters) or row['groupID'] in ( 1882, 1975, 1971, - 1983 # the "container" for the abysmal environments - ) # Abysmal weather (environment) + 1983 # the "container" for the abyssal environments + ) # Abyssal weather (environment) ): - eveTypes.add(row["typeID"]) + eveTypes.add(row['typeID']) # ignore checker def isIgnored(file, row): - if file in ("evetypes", "dgmtypeeffects", "dgmtypeattribs", "invmetatypes") and row['typeID'] not in eveTypes: + if file in ('evetypes', 'dgmtypeeffects', 'dgmtypeattribs', 'invmetatypes') and row['typeID'] not in eveTypes: return True return False @@ -234,31 +217,31 @@ def main(db, json_path): fieldMap = fieldMapping.get(jsonName, {}) tmp = [] - print("processing {}".format(jsonName)) + print('processing {}'.format(jsonName)) for row in table: # We don't care about some kind of rows, filter it out if so if not isIgnored(jsonName, row): - if jsonName == 'evetypes' and row["typeName"].startswith('Civilian'): # Apparently people really want Civilian modules available - row["published"] = True + if jsonName == 'evetypes' and row['typeName_en-us'].startswith('Civilian'): # Apparently people really want Civilian modules available + row['published'] = True instance = tables[jsonName]() # fix for issue 80 - if jsonName is "icons" and "res:/ui/texture/icons/" in str(row["iconFile"]).lower(): - row["iconFile"] = row["iconFile"].lower().replace("res:/ui/texture/icons/", "").replace(".png", "") + if jsonName is 'icons' and 'res:/ui/texture/icons/' in str(row['iconFile']).lower(): + row['iconFile'] = row['iconFile'].lower().replace('res:/ui/texture/icons/', '').replace('.png', '') # with res:/ui... references, it points to the actual icon file (including it's size variation of #_size_#) # strip this info out and get the identifying info split = row['iconFile'].split('_') if len(split) == 3: - row['iconFile'] = "{}_{}".format(split[0], split[2]) - if jsonName is "icons" and "modules/" in str(row["iconFile"]).lower(): - row["iconFile"] = row["iconFile"].lower().replace("modules/", "").replace(".png", "") + row['iconFile'] = '{}_{}'.format(split[0], split[2]) + if jsonName is 'icons' and 'modules/' in str(row['iconFile']).lower(): + row['iconFile'] = row['iconFile'].lower().replace('modules/', '').replace('.png', '') - if jsonName is "clonegrades": - if (row["alphaCloneID"] not in tmp): + if jsonName is 'clonegrades': + if (row['alphaCloneID'] not in tmp): cloneParent = eos.gamedata.AlphaClone() - setattr(cloneParent, "alphaCloneID", row["alphaCloneID"]) - setattr(cloneParent, "alphaCloneName", row["alphaCloneName"]) + setattr(cloneParent, 'alphaCloneID', row['alphaCloneID']) + setattr(cloneParent, 'alphaCloneName', row['alphaCloneName']) eos.db.gamedata_session.add(cloneParent) tmp.append(row['alphaCloneID']) @@ -274,15 +257,15 @@ def main(db, json_path): # CCP still has 5 subsystems assigned to T3Cs, even though only 4 are available / usable. They probably have some # old legacy requirement or assumption that makes it difficult for them to change this value in the data. But for # pyfa, we can do it here as a post-processing step - eos.db.gamedata_engine.execute("UPDATE dgmtypeattribs SET value = 4.0 WHERE attributeID = ?", (1367,)) + eos.db.gamedata_engine.execute('UPDATE dgmtypeattribs SET value = 4.0 WHERE attributeID = ?', (1367,)) - eos.db.gamedata_engine.execute("UPDATE invtypes SET published = 0 WHERE typeName LIKE '%abyssal%'") - print("done") + eos.db.gamedata_engine.execute('UPDATE invtypes SET published = 0 WHERE typeName LIKE '%abyssal%'') + print('done') -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="This scripts dumps effects from an sqlite cache dump to mongo") - parser.add_argument("-d", "--db", required=True, type=str, help="The sqlalchemy connectionstring, example: sqlite:///c:/tq.db") - parser.add_argument("-j", "--json", required=True, type=str, help="The path to the json dump") +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='This scripts dumps effects from an sqlite cache dump to mongo') + parser.add_argument('-d', '--db', required=True, type=str, help='The sqlalchemy connectionstring, example: sqlite:///c:/tq.db') + parser.add_argument('-j', '--json', required=True, type=str, help='The path to the json dump') args = parser.parse_args() main(args.db, args.json) From 6caa79c951ef6f24650bffc242fb12d3bf207dea Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Tue, 21 Aug 2018 19:43:41 +0300 Subject: [PATCH 7/8] Merge master into singularity --- scripts/jsonToSql.py | 40 +++++----------------------------------- 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/scripts/jsonToSql.py b/scripts/jsonToSql.py index 7326117b4..a99b9d0f6 100755 --- a/scripts/jsonToSql.py +++ b/scripts/jsonToSql.py @@ -25,11 +25,7 @@ import re # Add eos root path to sys.path so we can import ourselves path = os.path.dirname(__file__) -<<<<<<< HEAD sys.path.insert(0, os.path.realpath(os.path.join(path, '..'))) -======= -sys.path.insert(0, os.path.realpath(os.path.join(path, ".."))) ->>>>>>> master import json import argparse @@ -58,7 +54,6 @@ def main(db, json_path): # Config dict tables = { -<<<<<<< HEAD 'clonegrades': eos.gamedata.AlphaCloneSkill, 'dgmattribs': eos.gamedata.AttributeInfo, 'dgmeffects': eos.gamedata.Effect, @@ -74,22 +69,6 @@ def main(db, json_path): 'phbtraits': eos.gamedata.Traits, 'phbmetadata': eos.gamedata.MetaData, 'mapbulk_marketGroups': eos.gamedata.MarketGroup, -======= - "clonegrades": eos.gamedata.AlphaCloneSkill, - "dgmattribs": eos.gamedata.AttributeInfo, - "dgmeffects": eos.gamedata.Effect, - "dgmtypeattribs": eos.gamedata.Attribute, - "dgmtypeeffects": eos.gamedata.ItemEffect, - "dgmunits": eos.gamedata.Unit, - "evecategories": eos.gamedata.Category, - "evegroups": eos.gamedata.Group, - "invmetagroups": eos.gamedata.MetaGroup, - "invmetatypes": eos.gamedata.MetaType, - "evetypes": eos.gamedata.Item, - "phbtraits": eos.gamedata.Traits, - "phbmetadata": eos.gamedata.MetaData, - "mapbulk_marketGroups": eos.gamedata.MarketGroup, ->>>>>>> master } fieldMapping = { @@ -209,11 +188,7 @@ def main(db, json_path): tableData = convertIcons(tableData) if jsonName == 'phbtraits': tableData = convertTraits(tableData) -<<<<<<< HEAD if jsonName == 'clonegrades': -======= - if jsonName == "clonegrades": ->>>>>>> master tableData = convertClones(tableData) data[jsonName] = tableData @@ -282,7 +257,7 @@ def main(db, json_path): eos.db.gamedata_session.add(instance) # quick and dirty hack to get this data in - with open(os.path.join(jsonPath, "dynamicAttributes.json"), encoding="utf-8") as f: + with open(os.path.join(jsonPath, 'dynamicAttributes.json'), encoding='utf-8') as f: bulkdata = json.load(f) for mutaID, data in bulkdata.items(): muta = eos.gamedata.DynamicItem() @@ -311,23 +286,18 @@ def main(db, json_path): # pyfa, we can do it here as a post-processing step eos.db.gamedata_engine.execute('UPDATE dgmtypeattribs SET value = 4.0 WHERE attributeID = ?', (1367,)) -<<<<<<< HEAD - eos.db.gamedata_engine.execute('UPDATE invtypes SET published = 0 WHERE typeName LIKE '%abyssal%'') - print('done') -======= - eos.db.gamedata_engine.execute("UPDATE invtypes SET published = 0 WHERE typeName LIKE '%abyssal%'") + eos.db.gamedata_engine.execute('UPDATE invtypes SET published = 0 WHERE typeName LIKE \'%abyssal%\'') print() for x in CATEGORIES_TO_REMOVE: cat = eos.db.gamedata_session.query(eos.gamedata.Category).filter(eos.gamedata.Category.ID == x).first() - print ("Removing Category: {}".format(cat.name)) + print ('Removing Category: {}'.format(cat.name)) eos.db.gamedata_session.delete(cat) eos.db.gamedata_session.commit() - eos.db.gamedata_engine.execute("VACUUM") + eos.db.gamedata_engine.execute('VACUUM') - print("done") ->>>>>>> master + print('done') if __name__ == '__main__': parser = argparse.ArgumentParser(description='This scripts dumps effects from an sqlite cache dump to mongo') From ccbd0a117bd9b2f9c1a8ea52d76c3c14fa834655 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Tue, 21 Aug 2018 19:51:56 +0300 Subject: [PATCH 8/8] Fix merge issue --- scripts/jsonToSql.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/jsonToSql.py b/scripts/jsonToSql.py index a99b9d0f6..2d1b3ed01 100755 --- a/scripts/jsonToSql.py +++ b/scripts/jsonToSql.py @@ -60,7 +60,6 @@ def main(db, json_path): 'dgmtypeattribs': eos.gamedata.Attribute, 'dgmtypeeffects': eos.gamedata.ItemEffect, 'dgmunits': eos.gamedata.Unit, - 'icons': eos.gamedata.Icon, 'evecategories': eos.gamedata.Category, 'evegroups': eos.gamedata.Group, 'invmetagroups': eos.gamedata.MetaGroup,