You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
9.8 KiB
224 lines
9.8 KiB
import argparse
|
|
import pymysql
|
|
from time import time
|
|
import traceback
|
|
|
|
class DB_Connector:
|
|
def __init__(self, host, port, db, user, password):
|
|
self.connector = pymysql.connect(host = host, port = port, database=db, user = user, password=password, cursorclass=pymysql.cursors.DictCursor)
|
|
|
|
def execute(self, sql, payload = ()):
|
|
with self.connector.cursor() as cursor:
|
|
cursor.execute(sql, payload)
|
|
|
|
def cursor(self):
|
|
self.connector.commit()
|
|
|
|
|
|
class tf2idb:
|
|
def __init__(self, TF_FOLDER, DB_CONNECTOR, ITEMS_GAME = "scripts/items/items_game.txt"):
|
|
import vdf
|
|
import collections
|
|
import copy
|
|
|
|
def dict_merge(dct, merge_dct):
|
|
""" Recursive dict merge. Inspired by :meth:``dict.update()``, instead of
|
|
updating only top-level keys, dict_merge recurses down into dicts nested
|
|
to an arbitrary depth, updating keys. The ``merge_dct`` is merged into
|
|
``dct``.
|
|
:param dct: dict onto which the merge is executed
|
|
:param merge_dct: dct merged into dct
|
|
:return: None
|
|
"""
|
|
for k, v in merge_dct.items():
|
|
if (k == 'used_by_classes' or k == 'model_player_per_class'): #handles Demoman vs demoman... Valve pls
|
|
v = dict((k2.lower(), v2) for k2, v2 in v.items())
|
|
if (k in dct and isinstance(dct[k], dict) and isinstance(v, collections.abc.Mapping)):
|
|
dict_merge(dct[k], v)
|
|
else:
|
|
dct[k] = copy.deepcopy(v)
|
|
|
|
def resolve_prefabs(item, prefabs):
|
|
# generate list of prefabs
|
|
prefab_list = item.get('prefab', '').split()
|
|
for prefab in prefab_list:
|
|
subprefabs = prefabs[prefab].get('prefab', '').split()
|
|
prefab_list.extend(p for p in subprefabs if p not in prefab_list)
|
|
|
|
# iterate over prefab list and merge, nested prefabs first
|
|
result = {}
|
|
for prefab in ( prefabs[p] for p in reversed(prefab_list) ):
|
|
dict_merge(result, prefab)
|
|
|
|
dict_merge(result, item)
|
|
return result, prefab_list
|
|
|
|
data = None
|
|
|
|
ITEMS_GAME = TF_FOLDER + "/" + ITEMS_GAME
|
|
|
|
dbc = DB_CONNECTOR
|
|
|
|
with open(ITEMS_GAME) as f:
|
|
data = vdf.parse(f)
|
|
data = data['items_game']
|
|
|
|
dbc.execute('DROP TABLE IF EXISTS new_tf2idb_class')
|
|
dbc.execute('DROP TABLE IF EXISTS new_tf2idb_item_attributes')
|
|
dbc.execute('DROP TABLE IF EXISTS new_tf2idb_item')
|
|
dbc.execute('DROP TABLE IF EXISTS new_tf2idb_particles')
|
|
dbc.execute('DROP TABLE IF EXISTS new_tf2idb_equip_conflicts')
|
|
dbc.execute('DROP TABLE IF EXISTS new_tf2idb_equip_regions')
|
|
dbc.execute('DROP TABLE IF EXISTS new_tf2idb_capabilities')
|
|
dbc.execute('DROP TABLE IF EXISTS new_tf2idb_attributes')
|
|
dbc.execute('DROP TABLE IF EXISTS new_tf2idb_qualities')
|
|
|
|
dbc.execute('CREATE TABLE `new_tf2idb_class` (`id` INT NOT NULL , `class` VARCHAR(64) NOT NULL , `slot` VARCHAR(64) NULL, PRIMARY KEY (`id`, `class`)) ENGINE = InnoDB;')
|
|
dbc.execute('CREATE TABLE `new_tf2idb_item_attributes` (`id` INT NOT NULL, `attribute` INT NOT NULL, `value` VARCHAR(128) NOT NULL,`static` INT NULL, PRIMARY KEY (`id`, `attribute`)) ENGINE = InnoDB;'
|
|
)
|
|
dbc.execute('CREATE TABLE `new_tf2idb_item` (`id` INT PRIMARY KEY NOT NULL, `name` VARCHAR(128) NOT NULL, `item_name` VARCHAR(64) NULL, `class` VARCHAR(128) NOT NULL, `slot` VARCHAR(128) NULL, `quality` VARCHAR(128) NOT NULL, `tool_type` VARCHAR(128) NULL, `min_ilevel` INT NULL, `max_ilevel` INT NULL, `baseitem` INT NULL, `holiday_restriction` VARCHAR(128) NULL, `has_string_attribute` INT NULL, `propername` INT NULL )'
|
|
)
|
|
dbc.execute('CREATE TABLE `new_tf2idb_particles` (`id` INT PRIMARY KEY NOT NULL , `name` VARCHAR(128) NOT NULL )')
|
|
dbc.execute('CREATE TABLE `new_tf2idb_equip_conflicts` (`name` VARCHAR(128) NOT NULL , `region` VARCHAR(128) NOT NULL , PRIMARY KEY (`name`, `region`))')
|
|
dbc.execute('CREATE TABLE `new_tf2idb_equip_regions` (`id` INT NOT NULL , `region` VARCHAR(128) NOT NULL , PRIMARY KEY (`id`, `region`))')
|
|
dbc.execute('CREATE TABLE `new_tf2idb_capabilities` (`id` INT NOT NULL , `capability` VARCHAR(128) NOT NULL )')
|
|
dbc.execute('CREATE TABLE `new_tf2idb_attributes` ('
|
|
'`id` INT PRIMARY KEY NOT NULL,'
|
|
'`name` VARCHAR(128) NOT NULL,'
|
|
'`attribute_class` VARCHAR(128) NULL,'
|
|
'`attribute_type` VARCHAR(128) NULL,'
|
|
'`description_string` VARCHAR(128) NULL,'
|
|
'`description_format` VARCHAR(128) NULL,'
|
|
'`effect_type` VARCHAR(128) NULL,'
|
|
'`hidden` INT NULL,'
|
|
'`stored_as_integer` INT NULL,'
|
|
'`armory_desc` VARCHAR(128) NULL,'
|
|
'`is_set_bonus` INT NULL,'
|
|
'`is_user_generated` INT NULL,'
|
|
'`can_affect_recipe_component_name` INT NULL,'
|
|
'`apply_tag_to_item_definition` VARCHAR(128) NULL'
|
|
')'
|
|
)
|
|
dbc.execute('CREATE TABLE `new_tf2idb_qualities` (`name` VARCHAR(128) PRIMARY KEY NOT NULL , `value` INT NOT NULL )')
|
|
|
|
nonce = int(time())
|
|
dbc.execute('CREATE INDEX `tf2idb_item_attributes_%i` ON `new_tf2idb_item_attributes` (`attribute` ASC)' % nonce)
|
|
dbc.execute('CREATE INDEX `tf2idb_class_%i` ON `new_tf2idb_class` (`class` ASC)' % nonce)
|
|
dbc.execute('CREATE INDEX `tf2idb_item_%i` ON `new_tf2idb_item` (`slot` ASC)' % nonce)
|
|
|
|
|
|
# qualities
|
|
for qname,qdata in data['qualities'].items():
|
|
dbc.execute('INSERT INTO new_tf2idb_qualities (name, value) VALUES (%s,%s)', (qname, qdata['value']))
|
|
|
|
# particles
|
|
for particle_type, particle_list in data['attribute_controlled_attached_particles'].items():
|
|
for k,v in particle_list.items():
|
|
dbc.execute('INSERT INTO new_tf2idb_particles (id,name) VALUES (%s,%s)', (k, v['system']) ) #TODO add the other fields too
|
|
|
|
# attributes
|
|
attribute_type = {}
|
|
for k,v in data['attributes'].items():
|
|
at = v.get('attribute_type')
|
|
if at:
|
|
atype = at
|
|
else:
|
|
if v.get('stored_as_integer'):
|
|
atype = 'integer'
|
|
else:
|
|
atype = 'float'
|
|
attribute_type[v['name'].lower()] = (k, atype)
|
|
dbc.execute('INSERT INTO new_tf2idb_attributes (id,name,attribute_class,attribute_type,description_string,description_format,effect_type,hidden,stored_as_integer,armory_desc,is_set_bonus, is_user_generated,can_affect_recipe_component_name,apply_tag_to_item_definition) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)',
|
|
(k,v.get('name'),v.get('attribute_class'),v.get('attribute_type'),v.get('description_string'),v.get('description_format'),
|
|
v.get('effect_type'),v.get('hidden'),v.get('stored_as_integer'),v.get('armory_desc'),v.get('is_set_bonus'),
|
|
v.get('is_user_generated'),v.get('can_affect_recipe_component_name'),v.get('apply_tag_to_item_definition')
|
|
)
|
|
)
|
|
|
|
# conflicts
|
|
for k,v in data['equip_conflicts'].items():
|
|
for region in v.keys():
|
|
dbc.execute('INSERT INTO new_tf2idb_equip_conflicts (name,region) VALUES (%s,%s)', (k, region))
|
|
|
|
# items
|
|
for id,v in data['items'].items():
|
|
if id == 'default':
|
|
continue
|
|
i, prefabs_used = resolve_prefabs(v, data['prefabs'])
|
|
baseitem = 'baseitem' in i
|
|
|
|
try:
|
|
tool = None
|
|
if 'tool' in i:
|
|
tool = i['tool'].get('type')
|
|
|
|
has_string_attribute = False
|
|
if 'static_attrs' in i:
|
|
for name,value in i['static_attrs'].items():
|
|
aid,atype = attribute_type[name.lower()]
|
|
if atype == 'string':
|
|
has_string_attribute = True
|
|
dbc.execute('INSERT INTO new_tf2idb_item_attributes (id,attribute,value,static) VALUES (%s,%s,%s,%s)', (id,aid,value,1))
|
|
|
|
if 'attributes' in i:
|
|
for name,info in i['attributes'].items():
|
|
aid,atype = attribute_type[name.lower()]
|
|
if atype == 'string':
|
|
has_string_attribute = True
|
|
dbc.execute('INSERT INTO new_tf2idb_item_attributes (id,attribute,value,static) VALUES (%s,%s,%s,%s)', (id,aid,info['value'],0))
|
|
|
|
dbc.execute('INSERT INTO new_tf2idb_item '
|
|
'(id,name,item_name,class,slot,quality,tool_type,min_ilevel,max_ilevel,baseitem,holiday_restriction,has_string_attribute,propername) '
|
|
'VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)',
|
|
(id,i['name'],i.get('item_name'),i['item_class'],i.get('item_slot'),i.get('item_quality', ''), tool, i.get('min_ilevel'), i.get('max_ilevel'),baseitem,
|
|
i.get('holiday_restriction'), has_string_attribute, i.get('propername'))
|
|
)
|
|
|
|
if 'used_by_classes' in i:
|
|
for prof, val in i['used_by_classes'].items():
|
|
dbc.execute('INSERT INTO new_tf2idb_class (id,class,slot) VALUES (%s,%s,%s)', (id, prof.lower(), val if val != '1' else None))
|
|
|
|
region_field = i.get('equip_region') or i.get('equip_regions')
|
|
if region_field:
|
|
if type(region_field) is str:
|
|
region_field = {region_field: 1}
|
|
for region in region_field.keys():
|
|
dbc.execute('INSERT INTO new_tf2idb_equip_regions (id,region) VALUES (%s,%s)', (id, region))
|
|
|
|
# capabilties
|
|
for capability,val in i.get('capabilities', {}).items():
|
|
dbc.execute('INSERT INTO new_tf2idb_capabilities (id,capability) VALUES (%s,%s)', (id, (capability if val != '0' else '!'+capability)))
|
|
|
|
except:
|
|
traceback.print_exc()
|
|
print(id)
|
|
raise
|
|
|
|
def replace_table(name):
|
|
dbc.execute('DROP TABLE IF EXISTS %s' % name)
|
|
dbc.execute('ALTER TABLE new_%s RENAME TO %s' % (name,name))
|
|
|
|
replace_table('tf2idb_class')
|
|
replace_table('tf2idb_item_attributes')
|
|
replace_table('tf2idb_item')
|
|
replace_table('tf2idb_particles')
|
|
replace_table('tf2idb_equip_conflicts')
|
|
replace_table('tf2idb_equip_regions')
|
|
replace_table('tf2idb_capabilities')
|
|
replace_table('tf2idb_attributes')
|
|
replace_table('tf2idb_qualities')
|
|
|
|
dbc.commit()
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("tf_directory", type=str, default="")
|
|
parser.add_argument("--host", type=str, default="localhost")
|
|
parser.add_argument("--port", type=int, default=3306)
|
|
parser.add_argument("db", type=str, default="")
|
|
parser.add_argument("user", type=str, default="")
|
|
parser.add_argument("password", type=str, default="")
|
|
args = parser.parse_args()
|
|
c = DB_Connector(args.host, args.port, args.db, args.user, args.password)
|
|
tf2idb(args.tf_directory, c)
|
|
|
|
|