Browse Source

add tf2idb support and more

master
server 3 years ago
parent
commit
57b81a3391
  1. 298
      SourceManager.py

298
SourceManager.py

@ -1,4 +1,4 @@
#!/usr/bin/python3
#!/usr/bin/python3.6
VERSION = 1.0
#SYS IMPORTS
@ -27,14 +27,14 @@ DEBUG = 0
ALL_YES = 0
class colors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
class new_o:
def __init__(self, server_name):
@ -89,6 +89,228 @@ def create_symbolic_file(source_file, symbolic_file):
print(f"Execute system cmd: {cmd}")
SCall(cmd.split())
class tf2idb:
def __init__(self, TF_FOLDER, ITEMS_GAME, DB_FILE):
import vdf
import sqlite3
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.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
DB_FILE = TF_FOLDER + "/" + DB_FILE
db = sqlite3.connect(DB_FILE)
dbc = db.cursor()
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" INTEGER NOT NULL , "class" TEXT NOT NULL , "slot" TEXT , PRIMARY KEY ("id", "class"))')
dbc.execute('CREATE TABLE "new_tf2idb_item_attributes" ('
'"id" INTEGER NOT NULL,'
'"attribute" INTEGER NOT NULL,'
'"value" TEXT NOT NULL,'
'"static" INTEGER,'
'PRIMARY KEY ("id", "attribute")'
')'
)
dbc.execute('CREATE TABLE "new_tf2idb_item" ('
'"id" INTEGER PRIMARY KEY NOT NULL,'
'"name" TEXT NOT NULL,'
'"item_name" TEXT,'
'"class" TEXT NOT NULL,'
'"slot" TEXT,'
'"quality" TEXT NOT NULL,'
'"tool_type" TEXT,'
'"min_ilevel" INTEGER,'
'"max_ilevel" INTEGER,'
'"baseitem" INTEGER,'
'"holiday_restriction" TEXT,'
'"has_string_attribute" INTEGER,'
'"propername" INTEGER'
')'
)
dbc.execute('CREATE TABLE "new_tf2idb_particles" ("id" INTEGER PRIMARY KEY NOT NULL , "name" TEXT NOT NULL )')
dbc.execute('CREATE TABLE "new_tf2idb_equip_conflicts" ("name" TEXT NOT NULL , "region" TEXT NOT NULL , PRIMARY KEY ("name", "region"))')
dbc.execute('CREATE TABLE "new_tf2idb_equip_regions" ("id" INTEGER NOT NULL , "region" TEXT NOT NULL , PRIMARY KEY ("id", "region"))')
dbc.execute('CREATE TABLE "new_tf2idb_capabilities" ("id" INTEGER NOT NULL , "capability" TEXT NOT NULL )')
dbc.execute('CREATE TABLE "new_tf2idb_attributes" ('
'"id" INTEGER PRIMARY KEY NOT NULL,'
'"name" TEXT NOT NULL,'
'"attribute_class" TEXT,'
'"attribute_type" TEXT,'
'"description_string" TEXT,'
'"description_format" TEXT,'
'"effect_type" TEXT,'
'"hidden" INTEGER,'
'"stored_as_integer" INTEGER,'
'"armory_desc" TEXT,'
'"is_set_bonus" INTEGER,'
'"is_user_generated" INTEGER,'
'"can_affect_recipe_component_name" INTEGER,'
'"apply_tag_to_item_definition" TEXT'
')'
)
dbc.execute('CREATE TABLE "new_tf2idb_qualities" ("name" TEXT PRIMARY KEY NOT NULL , "value" INTEGER 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 (?,?)', (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 (?,?)', (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 (?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
(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 (?,?)', (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 (?,?,?,?)', (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 (?,?,?,?)', (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 (?,?,?,?,?,?,?,?,?,?,?,?,?)',
(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 (?,?,?)', (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 (?,?)', (id, region))
# capabilties
for capability,val in i.get('capabilities', {}).items():
dbc.execute('INSERT INTO new_tf2idb_capabilities (id,capability) VALUES (?,?)', (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')
db.commit()
dbc.execute('VACUUM')
class Manager:
servers = []
max_lines = 4
@ -235,7 +457,36 @@ class Server:
self.o.info("Send sm plugins refresh command...", end = "\t")
self.rcon("sm plugins refresh", hide_server_name=True)
return True
def clear_maps(self, exclude = "itemtest.bsp"):
map_list = glob(f"{self.root}/maps/*.bsp")
self.o.info(f"Delete {len(map_list) - 1} maps?")
if self.wait_input():
for map_path in map_list:
if exclude in map_path:
continue
remove_file(map_path)
return True
def clear_download_cache(self):
cache_files = glob(f"{self.root}/download/user_custom/*/*.dat")
self.o.info(f"Delete {len(cache_files)} cache files?")
if not self.wait_input():
return True
count = 0
for cache_file in cache_files:
try:
remove_file(cache_file)
count += 1
except Exception as delete_error:
print(cache_file, delete_error)
sys.exit(1)
self.o.info(f"Deleted {count} cache files")
return True
def upgrade_plugin(self, fresh_path, need_reloads_plugins = True):
new_hash = hashfile(fresh_path)
fresh_plugin_name = fresh_path.split("/")[-1:][0]
@ -256,7 +507,15 @@ class Server:
return True
self.o.info("Upgraded plugin not found in server...")
return False
def update_tf2idb(self):
from sqlite3 import OperationalError
self.o.info("Updating TF2IDB")
try:
tf2idb(self.root, "scripts/items/items_game.txt", "addons/sourcemod/data/sqlite/tf2idb.sq3")
except OperationalError:
self.o.error("Cannot find database file")
def wait_input(self, yes = "y", no = "n"):
if ALL_YES:
@ -612,6 +871,11 @@ if __name__ == "__main__":
parser.add_argument("--UpgradePlugin", "-upg", help = "Path of file to uprade. Names must match.", type = str, default = "")
parser.add_argument("--NoReloadPlugins", "-nrp", help = "Upgrade plugins without send sm plugins refresh command", default = False, action = "store_true")
################################################################################################################################################
parser.add_argument("--DeleteDownloadCache", "-ddc", help = "Clear download cache", default = False, action = "store_true")
parser.add_argument("--DeleteUnusedMaps", "-dum", help = "Delete maps from maps folder", default = False, action = "store_true")
################################################################################################################################################
parser.add_argument("--UpdateTF2IDB", help = "Update tf2idb database", default = False, action = "store_true")
################################################################################################################################################
args = parser.parse_args()
ALL_YES = 1 if args.yes else 0
##################################
@ -701,3 +965,15 @@ if __name__ == "__main__":
else:
o.error("Invalid name of remove plugin!")
sys.exit(1)
###################################
if args.DeleteDownloadCache:
manager.execute("clear_download_cache")
sys.exit(0)
###################################
if args.DeleteUnusedMaps:
manager.execute("clear_maps")
sys.exit(0)
###################################
if args.UpdateTF2IDB:
manager.execute("update_tf2idb")
sys.exit(0)
Loading…
Cancel
Save