cdclient and some analysis commands

This commit is contained in:
Aaron Kimbre 2022-07-14 08:31:31 -05:00
parent 62fb9a3c01
commit 92f7e5ae52
6 changed files with 305 additions and 48 deletions

2
.gitignore vendored
View File

@ -17,3 +17,5 @@ property_files/*
*.log
app/settings.py
*.exe
*.csv
*.sql

View File

@ -18,7 +18,11 @@ from app.commands import (
load_property,
gen_image_cache,
gen_model_cache,
fix_clone_ids
fix_clone_ids,
parse_lucache,
makeup_unlisted_objects,
gen_new_locales,
xref_scripts
)
from app.models import Account, AccountInvitation, AuditLog
@ -81,6 +85,10 @@ def create_app():
app.cli.add_command(gen_image_cache)
app.cli.add_command(gen_model_cache)
app.cli.add_command(fix_clone_ids)
app.cli.add_command(parse_lucache)
app.cli.add_command(makeup_unlisted_objects)
app.cli.add_command(gen_new_locales)
app.cli.add_command(xref_scripts)
register_logging(app)
register_settings(app)

View File

@ -1408,58 +1408,89 @@ class ComponentsRegistry(db.Model):
nullable=False
)
component = generic_relationship(component_type, component_id)
# component = generic_relationship(component_type, component_id)
# From DLU source
class ComponentType(enum.IntEnum):
COMPONENT_TYPE_CONTROLLABLE_PHYSICS = 1 # The ControllablePhysics Component
COMPONENT_TYPE_RENDER = 2 # The Render Component
COMPONENT_TYPE_SIMPLE_PHYSICS = 3 # The SimplePhysics Component
COMPONENT_TYPE_CHARACTER = 4 # The Character Component
COMPONENT_TYPE_SCRIPT = 5 # The Script Component
COMPONENT_TYPE_BOUNCER = 6 # The Bouncer Component
COMPONENT_TYPE_BUFF = 7 # The Buff Component
COMPONENT_TYPE_SKILL = 9 # The Skill Component
COMPONENT_TYPE_ITEM = 11 # The Item Component
COMPONENT_TYPE_VENDOR = 16 # The Vendor Component
COMPONENT_TYPE_INVENTORY = 17 # The Inventory Component
COMPONENT_TYPE_SHOOTING_GALLERY = 19 # The Shooting Gallery Component
COMPONENT_TYPE_RIGID_BODY_PHANTOM_PHYSICS = 20 # The RigidBodyPhantomPhysics Component
COMPONENT_TYPE_COLLECTIBLE = 23 # The Collectible Component
COMPONENT_TYPE_MOVING_PLATFORM = 25 # The MovingPlatform Component
COMPONENT_TYPE_PET = 26 # The Pet Component
COMPONENT_TYPE_VEHICLE_PHYSICS = 30 # The VehiclePhysics Component
COMPONENT_TYPE_MOVEMENT_AI = 31 # The MovementAI Component
COMPONENT_TYPE_PROPERTY = 36 # The Property Component
COMPONENT_TYPE_SCRIPTED_ACTIVITY = 39 # The ScriptedActivity Component
COMPONENT_TYPE_PHANTOM_PHYSICS = 40 # The PhantomPhysics Component
COMPONENT_TYPE_PROPERTY_ENTRANCE = 43 # The PhantomPhysics Component
COMPONENT_TYPE_PROPERTY_MANAGEMENT = 45 # The PropertyManagement Component
COMPONENT_TYPE_REBUILD = 48 # The Rebuild Component
COMPONENT_TYPE_SWITCH = 49 # The Switch Component
COMPONENT_TYPE_ZONE_CONTROL = 50 # The ZoneControl Component
COMPONENT_TYPE_PACKAGE = 53 # The Package Component
COMPONENT_TYPE_PLAYER_FLAG = 58 # The PlayerFlag Component
COMPONENT_TYPE_BASE_COMBAT_AI = 60 # The BaseCombatAI Component
COMPONENT_TYPE_MODULE_ASSEMBLY = 61 # The ModuleAssembly Component
COMPONENT_TYPE_PROPERTY_VENDOR = 65 # The PropertyVendor Component
COMPONENT_TYPE_ROCKET_LAUNCH = 67 # The RocketLaunch Component
COMPONENT_TYPE_RACING_CONTROL = 71 # The RacingControl Component
COMPONENT_TYPE_MISSION_OFFER = 73 # The MissionOffer Component
COMPONENT_TYPE_EXHIBIT = 75 # The Exhibit Component
COMPONENT_TYPE_RACING_STATS = 74 # The Exhibit Component
COMPONENT_TYPE_SOUND_TRIGGER = 77 # The Sound Trigger Component
COMPONENT_TYPE_PROXIMITY_MONITOR = 78 # The Proximity Monitor Component
COMPONENT_TYPE_MISSION = 84 # The Mission Component
COMPONENT_TYPE_ROCKET_LAUNCH_LUP = 97 # The LUP Launchpad Componen
COMPONENT_TYPE_RAIL_ACTIVATOR = 104
COMPONENT_TYPE_POSSESSOR = 107 # The Component 107
COMPONENT_TYPE_POSSESSABLE = 108 # The Component 108
COMPONENT_TYPE_BUILD_BORDER = 114 # The Build Border Component
COMPONENT_TYPE_DESTROYABLE = 1000 # The Destroyable Component
COMPONENT_TYPE_CONTROLLABLE_PHYSICS = 1 # noqa - The ControllablePhysics Component
COMPONENT_TYPE_RENDER = 2 # noqa - The Render Component
COMPONENT_TYPE_SIMPLE_PHYSICS = 3 # noqa - The SimplePhysics Component
COMPONENT_TYPE_CHARACTER = 4 # noqa - The Character Component
COMPONENT_TYPE_SCRIPT = 5 # noqa - The Script Component
COMPONENT_TYPE_BOUNCER = 6 # noqa - The Bouncer Component
COMPONENT_TYPE_BUFF = 7 # noqa - The Buff Component
COMPONENT_TYPE_SKILL = 9 # noqa - The Skill Component
COMPONENT_TYPE_ITEM = 11 # noqa - The Item Component
COMPONENT_TYPE_VENDOR = 16 # noqa - The Vendor Component
COMPONENT_TYPE_INVENTORY = 17 # noqa - The Inventory Component
COMPONENT_TYPE_SHOOTING_GALLERY = 19 # noqa - The Shooting Gallery Component
COMPONENT_TYPE_RIGID_BODY_PHANTOM_PHYSICS = 20 # noqa - The RigidBodyPhantomPhysics Component
COMPONENT_TYPE_COLLECTIBLE = 23 # noqa - The Collectible Component
COMPONENT_TYPE_MOVING_PLATFORM = 25 # noqa - The MovingPlatform Component
COMPONENT_TYPE_PET = 26 # noqa - The Pet Component
COMPONENT_TYPE_VEHICLE_PHYSICS = 30 # noqa - The VehiclePhysics Component
COMPONENT_TYPE_MOVEMENT_AI = 31 # noqa - The MovementAI Component
COMPONENT_TYPE_PROPERTY = 36 # noqa - The Property Component
COMPONENT_TYPE_SCRIPTED_ACTIVITY = 39 # noqa - The ScriptedActivity Component
COMPONENT_TYPE_PHANTOM_PHYSICS = 40 # noqa - The PhantomPhysics Component
COMPONENT_TYPE_PROPERTY_ENTRANCE = 43 # noqa - The PhantomPhysics Component
COMPONENT_TYPE_PROPERTY_MANAGEMENT = 45 # noqa - The PropertyManagement Component
COMPONENT_TYPE_REBUILD = 48 # noqa - The Rebuild Component
COMPONENT_TYPE_SWITCH = 49 # noqa - The Switch Component
COMPONENT_TYPE_ZONE_CONTROL = 50 # noqa - The ZoneControl Component
COMPONENT_TYPE_PACKAGE = 53 # noqa - The Package Component
COMPONENT_TYPE_PLAYER_FLAG = 58 # noqa - The PlayerFlag Component
COMPONENT_TYPE_BASE_COMBAT_AI = 60 # noqa - The BaseCombatAI Component
COMPONENT_TYPE_MODULE_ASSEMBLY = 61 # noqa - The ModuleAssembly Component
COMPONENT_TYPE_PROPERTY_VENDOR = 65 # noqa - The PropertyVendor Component
COMPONENT_TYPE_ROCKET_LAUNCH = 67 # noqa - The RocketLaunch Component
COMPONENT_TYPE_RACING_CONTROL = 71 # noqa - The RacingControl Component
COMPONENT_TYPE_MISSION_OFFER = 73 # noqa - The MissionOffer Component
COMPONENT_TYPE_EXHIBIT = 75 # noqa - The Exhibit Component
COMPONENT_TYPE_RACING_STATS = 74 # noqa - The Exhibit Component
COMPONENT_TYPE_SOUND_TRIGGER = 77 # noqa - The Sound Trigger Component
COMPONENT_TYPE_PROXIMITY_MONITOR = 78 # noqa - The Proximity Monitor Component
COMPONENT_TYPE_MISSION = 84 # noqa - The Mission Component
COMPONENT_TYPE_ROCKET_LAUNCH_LUP = 97 # noqa - The LUP Launchpad Componen
COMPONENT_TYPE_RAIL_ACTIVATOR = 104 # noqa
COMPONENT_TYPE_POSSESSOR = 107 # noqa - The Component 107
COMPONENT_TYPE_POSSESSABLE = 108 # noqa - The Component 108
COMPONENT_TYPE_BUILD_BORDER = 114 # noqa - The Build Border Component
COMPONENT_TYPE_DESTROYABLE = 1000 # noqa - The Destroyable Component
# class ComponentMap(enum.Enum):
# 1 = ["PhysicsComponent"]
# 2 = ["RenderComponent"]
# 3 = ["PhysicsComponent"]
# 5 = ["ScriptComponent"]
# 7 = ["DestructibleComponent"]
# 9 = ["ObjectSkills", "SkillBehavior"]
# 12 = ["RebuildComponent"]
# 15 = ["RenderComponent"]
# 17 = ["InventoryComponent"]
# 18 = ["PhysicsComponent"]
# 20 = ["PhysicsComponent"]
# 24 = ["Blueprints"]
# 26 = ["PetComponent"]
# 29 = ["JetPackPadComponent"]
# 30 = ["VehiclePhysics"]
# 31 = ["MovementAIComponent"]
# 33 = ["mapIcon", "NpcIcons"]
# 40 = ["PhysicsComponent"]
# 46 = ["PhysicsComponent"]
# 47 = ["PhysicsComponent"]
# 48 = ["RebuildComponent"]
# 52 = ["ChoiceBuildComponent"]
# 53 = ["PackageComponent"]
# 60 = ["BaseCombatAIComponent"]
# 61 = ["ModularBuildComponent"]
# 67 = ["RocketLaunchpadControlComponent"]
# 73 = ["MissionNPCComponent"]
# 75 = ["LUPExhibitComponent"]
# 78 = ["ProximityMonitor"]
class ControlSchemes(db.Model):
__tablename__ = 'ControlSchemes'
__bind_key__ = 'cdclient'

View File

@ -15,7 +15,17 @@ from multiprocessing import Pool
from functools import partial
from sqlalchemy import func
import time
import csv
import json
from app.cdclient import (
ComponentsRegistry,
RenderComponent,
ItemComponent,
Objects,
ScriptComponent,
)
from app.luclient import translate_from_locale
@click.command("init_db")
@click.argument('drop_tables', nargs=1)
@ -180,6 +190,187 @@ def load_property(zone, player):
)
new_prop_content.save()
@click.command("parse_lucache")
@with_appcontext
def parse_lucache():
"""Parses lucache csv file dump from nexus hq"""
unlisted_ids = [146, 147, 938, 1180, 1692, 1715, 1797, 1799, 1824, 1846, 1847, 1848, 1849, 1850, 1872, 1877, 1887, 1928, 1937, 1968, 1970, 1971, 1972, 1974, 1976, 1977, 1978, 1979, 1980, 1981, 1983, 1984, 2189, 2401, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2416, 2417, 2418, 2420, 2421, 2422, 2423, 2424, 2425, 2426, 2427, 2429, 2430, 2431, 2432, 2433, 2434, 2435, 2436, 2529, 2530, 2553, 2583, 2655, 2656, 2669, 2947, 2948, 3009, 3058, 3068, 3078, 3807, 3812, 3937, 4828, 4874, 4875, 4876, 4877, 4943, 4954, 5839, 5840, 6196, 6218, 6219, 6221, 6433, 6471, 6696, 6821, 6877, 6888, 6889, 6891, 6892, 6893, 6894, 6896, 6897, 6983, 7277, 7551, 7552, 7553, 7554, 7609, 7701, 7713, 7723, 7753, 7754, 7755, 7756, 7760, 7777, 7791, 7824, 7872, 8046, 8053, 8146, 9865, 9866, 9867, 9868, 10126, 10291, 10292, 10293, 10294, 10518, 10630, 10631, 10987, 11511, 11512, 11513, 11514, 11515, 11516, 11517, 11518, 11519, 11520, 11521, 11522, 11523, 11524, 11525, 12096, 12097, 12099, 12100, 12104, 12105, 12111, 12112, 12113, 12324, 12325, 12326, 12553, 12666, 12668, 12670, 12671, 12673, 12674, 12676, 12679, 12680, 12683, 12684, 12685, 12687, 12692, 12694, 12697, 12699, 12701, 12703, 12704, 12713, 12716, 12717, 12727, 12736, 12738, 12739, 12745, 12746, 12750, 12751, 12752, 12757, 12787, 12790, 12791, 12794, 12795, 12799, 12800, 12803, 12887, 12888, 12902, 12904, 12905, 12906, 12907, 12941, 13060, 13061, 13071, 13075, 13076, 13077, 13092, 13093, 13094, 13106, 13118, 13121, 13126, 13127, 13150, 13191, 13192, 13275, 13276, 13277, 13278, 13280, 13295, 13410, 13411, 13510, 13638, 13740, 13742, 13776, 13782, 13905, 13925, 13926, 13927, 13928, 13929, 13930, 13931, 13932, 13953, 13958, 13974, 13996, 13997, 13998, 13999, 14000, 14001, 14002, 14056, 14057, 14058, 14059, 14060, 14061, 14062, 14063, 14064, 14065, 14066, 14067, 14068, 14069, 14070, 14071, 14072, 14073, 14074, 14075, 14076, 14077, 14078, 14079, 14080, 14081, 14090, 14094, 14111, 14135, 14140, 14170, 14171, 14188, 14200, 14202, 14206, 14207, 14208, 14209, 14210, 14211, 14212, 14213, 14228, 14229, 14314, 14428, 14483, 14515, 14522, 14531, 14535, 14536, 14538, 14548, 14554, 14587, 14588, 14589, 14597, 14598, 14599, 14605, 14607, 14608, 14609, 14610, 14611, 14612, 14613, 14614, 14615, 14616, 14617, 14618, 14619, 14620, 14621, 14622, 14623, 14624, 14625, 14626, 14627, 14628, 14629, 14630, 14631, 14632, 14633, 14634, 14635, 14636, 14637, 14638, 14639, 14640, 14641, 14642, 14643, 14644, 14645, 14646, 14647, 14648, 14649, 14650, 14651, 14652, 14653, 14654, 14655, 14656, 14657, 14658, 14659, 14660, 14661, 14662, 14663, 14664, 14665, 14666, 14667, 14668, 14686, 14687, 14688, 14689, 14690, 14704, 14706, 14707, 14716, 14717, 14721, 14722, 14727, 14728, 14729, 14779, 14795, 14799, 14800, 14803, 14815, 14820, 14821, 14822, 14823, 14824, 14825, 14826, 14827, 14831, 14832, 14838, 14839, 15852, 15853, 15854, 15855, 15856, 15857, 15858, 15859, 15860, 15861, 15862, 15863, 15864, 15865, 15885, 15886, 15887, 15888, 15889, 15893, 15894, 15898, 15921, 15923, 15925, 15928, 15930, 15931, 15932, 15933, 15934, 15938, 15939, 15940, 15941, 15942, 15945, 15958, 15962, 15963, 15964, 15965, 15966, 15967, 15968, 15969, 15970, 15971, 15972, 15973, 15981, 15984, 15985, 15986, 15987, 15988, 15989, 15996, 15997, 15998, 15999, 16000, 16001, 16002, 16003, 16004, 16005, 16007, 16008, 16009, 16010, 16011, 16025, 16026, 16027, 16028, 16036, 16039, 16042, 16046, 16051, 16056, 16071, 16072, 16073, 16074, 16075, 16077, 16078, 16079, 16080, 16081, 16089, 16090, 16091, 16092, 16108, 16109, 16110, 16111, 16112, 16113, 16114, 16115, 16116, 16117, 16124, 16125, 16126, 16127, 16128, 16129, 16130, 16137, 16138, 16139, 16140, 16142, 16145, 16167, 16168, 16169, 16170, 16171, 16172, 16173, 16174, 16175, 16176, 16177, 16200, 16201, 16202, 16204, 16212, 16253, 16254, 16418, 16437, 16469, 16479, 16489, 16505, 16641, 16645, 16646, 16648, 16655, 16658, 16659, 16660, 16661, 16662, 16665, 16666, 16667, 16668, 16669, 16670, 16671, 16672, 16673, 16674, 16675, 16676, 16677, 16678, 16679, 16680, 16681, 16685, 16686, 16687, 16688, 16689, 16690, 16691, 16692, 16693, 16694, 16695, 16696, 16697, 16698, 16699, 16700, 16701, 16702, 16703, 16704, 16705, 16706, 16707, 16708, 16709, 16712, 16714, 16717, 16718, 16719, 16720, 16721, 16722, 16724, 16725, 16726, 16727, 16732, 16733, 16734, 16735] # noqa
with open("lucache.csv") as cache_file:
csv_reader = csv.reader(cache_file, delimiter=',')
line_count = 0
for row in csv_reader:
if row[0] == "id":
continue
if int(row[0]) in unlisted_ids:
json_data = json.loads(row[2])
components = ComponentsRegistry.query.filter(ComponentsRegistry.id == int(row[0])).all()
obj_type = "Environmental"
desc = json_data["Description"]
if desc in ["None", None, ""]:
desc = row[1]
nametag = 0
npcTemplateID = "null"
for comp in components:
if comp.component_type == 7: # Item
obj_type = "Smashable"
if comp.component_type == 11: # Item
obj_type = "Loot"
if comp.component_type == 35: # minifig
obj_type = "NPC"
npcTemplateID = comp.component_id
nametag = 1
if comp.component_type == 42: # b3
obj_type = "Behavior"
if comp.component_type == 60: # base combat ai
obj_type = "Enemy"
if comp.component_type == 73: # mission giver
if obj_type != "NPC":
obj_type = "Structure"
desc = f"__MG__{desc}"
if "vendor" in row[1].lower():
obj_type = "NPC"
print(f"""INSERT INTO "Objects" ("id","name","placeable","type","description","localize","npcTemplateID","displayName","interactionDistance","nametag","_internalNotes","locStatus","gate_version","HQ_valid") VALUES ("{row[0]}", "{row[1].replace("_", " ")}", 1, "{obj_type}", "{desc}", 1, {npcTemplateID} , "{json_data["DisplayName"]}", null , {nametag}, "Unlisted Object", 0, null, 1);""")
if obj_type in ["NPC", "Smashable", "Loot"]:
print(f""" <phrase id="Objects_{row[0]}_name">
<translation locale="en_US">{row[1]}</translation>
<translation locale="de_DE">TRASNSLATE UNLISTED</translation>
<translation locale="en_GB">{row[1]}</translation>
</phrase>
<phrase id="Objects_{row[0]}_description">
<translation locale="en_US">{desc}</translation>
<translation locale="de_DE">TRASNSLATE UNLISTED</translation>
<translation locale="en_GB">{desc}</translation>
</phrase>""")
# print(f'{row[0]}: {json_data["DisplayName"]}')
line_count += 1
# print(f'Processed {line_count} lines.')
@click.command("makeup_unlisted_objects")
@with_appcontext
def makeup_unlisted_objects():
objs_left = []
for obj in objs_left:
obj_type = "Environmental"
nametag = 0
name = "Name Missing"
desc = "null"
npcTemplateID = "null"
components = ComponentsRegistry.query.filter(ComponentsRegistry.id == obj).all()
for comp in components:
if comp.component_type == 2: # render
render = RenderComponent.query.filter(RenderComponent.id == comp.component_id).first()
if render is not None:
if render.render_asset not in [None, ""]:
name = render.render_asset.replace("_", " ").split('\\')[-1].split('/')[-1].split('.')[0].lower()
if name == "Name Missing":
if render.icon_asset not in [None, ""]:
name = render.icon_asset.replace("_", " ").split('\\')[-1].split('/')[-1].split('.')[0].lower()
name = name.replace("env ", "").replace("obj ", "").replace("minifig accessory ", "").replace("", "").replace("mf ", "").replace("cre ", "")
# print(f"{obj}: {name} : {alt_name}")
obj_type = "Smashable"
# else:
# print(f"{obj}: No Render")
if comp.component_type == 7: # destroyable
obj_type = "Smashable"
if comp.component_type == 11: # Item
item = ItemComponent.query.filter(ItemComponent.id == comp.component_id).first()
if item.itemType == 24:
obj_type = "Mount"
else:
obj_type = "Loot"
if comp.component_type == 35: # minifig
obj_type = "NPC"
npcTemplateID = comp.component_id
nametag = 1
if comp.component_type == 42: # b3
obj_type = "Behavior"
if comp.component_type == 60: # base combat ai
obj_type = "Enemy"
if comp.component_type == 73: # mission giver
if obj_type != "NPC":
obj_type = "Structure"
desc = f"__MG__{name}"
# print(f"""INSERT INTO "Objects" ("id","name","placeable","type","description","localize","npcTemplateID","displayName","interactionDistance","nametag","_internalNotes","locStatus","gate_version","HQ_valid") VALUES ("{obj}", "{name}", 1, "{obj_type}", "{desc}", 1, {npcTemplateID} , "{name}", null , {nametag}, "Unlisted Object", 0, null, 1);""")
if name != "Name Missing" and obj_type in ["Mount"]:
print(f""" <phrase id="Objects_{obj}_name">
<translation locale="en_US">{name}</translation>
<translation locale="de_DE">TRASNSLATE UNLISTED</translation>
<translation locale="en_GB">{name}</translation>
</phrase>""")
@click.command("gen_new_locales")
@with_appcontext
def gen_new_locales():
objects = Objects.query.order_by(Objects.id).all()
for obj in objects:
if obj.type == "Loot":
if obj.name not in ["Name Missing", None, "None"] and obj.name[:1] != "m":
name_to_trans = f"Object_{obj.id}_name"
name_transed = translate_from_locale(name_to_trans)
if name_to_trans == name_transed:
print(f""" <phrase id="Objects_{obj.id}_name">
<translation locale="en_US">{obj.name}</translation>
<translation locale="de_DE">TRASNSLATE OLD</translation>
<translation locale="en_GB">{obj.name}</translation>
</phrase>""")
if obj.description not in ["None", None, ""]:
description_to_trans = f"Object_{obj.id}_description"
description_transed = translate_from_locale(description_to_trans)
if description_to_trans == description_transed:
print(f""" <phrase id="Objects_{obj.id}_description">
<translation locale="en_US">{obj.description}</translation>
<translation locale="de_DE">TRASNSLATE OLD</translation>
<translation locale="en_GB">{obj.description}</translation>
</phrase>""")
@click.command("xref_scripts")
@with_appcontext
def xref_scripts():
"""cross refernce scripts dir with script component table"""
scripts = ScriptComponent.query.all()
base = 'app/luclient/res/'
server = 0
server_total = 0
client = 0
client_total = 0
server_used = 0
client_used = 0
used_total = 0
disk_scripts = [path for path in pathlib.Path('app/luclient/res/scripts').rglob("*.lua") if path.is_file()]
for script in scripts:
script_comps = ComponentsRegistry.query.filter(ComponentsRegistry.component_type == 5).filter(ComponentsRegistry.component_id == script.id).all()
if len(script_comps) > 0:
used_total += 1
if script.client_script_name not in [None, ""]:
cleaned_name = script.client_script_name.replace('\\', '/').lower()
client_script = pathlib.Path(f"{base}{cleaned_name}")
client_total += 1
if not client_script.is_file():
print(f"Missing Server Script: {client_script.as_posix()}")
client += 1
if len(script_comps) > 0:
client_used += 1
if script.script_name not in [None, ""]:
cleaned_name = script.script_name.replace('\\', '/').lower()
server_script = pathlib.Path(f"{base}{cleaned_name}")
server_total += 1
if not server_script.is_file():
print(f"Missing Client Script: {server_script.as_posix()}")
server += 1
if len(script_comps) > 0:
server_used += 1
print(f"Missing {server}/{server_total} server scripts")
print(f"Missing {client}/{client_total} client scripts")
print(f"Missing {server_used}/{used_total} used server scripts")
print(f"Missing {client_used}/{used_total} used client scripts")
print(f"Total cdclient scripts {server_total + client_total}\nTotal disk scripts {len(disk_scripts)}")
@click.command("gen_image_cache")
def gen_image_cache():

View File

@ -7,6 +7,11 @@ APP_SYSTEM_ERROR_SUBJECT_LINE = APP_NAME + " system error"
APP_SECRET_KEY = ""
APP_DATABASE_URI = "mysql+pymysql://<username>:<password>@<host>:<port>/<database>"
CONFIG_LINK = False
CONFIG_LINK_TITLE = ""
CONFIG_LINK_HREF = ""
CONFIG_LINK_TEXT = ""
# Send Analytics for Developers to better fix issues
ALLOW_ANALYTICS = False

View File

@ -24,7 +24,27 @@
</div>
{% endfor %}
<hr>
</div>
</div>
<div class='card mx-auto mt-5 shadow-sm bg-dark border-primary'>
<div class="card-body">
<h4 class="text-center">Links</h4>
{% if config.CONFIG_LINK %}
<div class="row">
<div class="col text-right">
{{ config.CONFIG_LINK_TITLE }}
</div>
<div class="col">
<a href="{{ url_for('static', filename=config.CONFIG_LINK_HREF) }}">
{{ config.CONFIG_LINK_TEXT }}
</a>
</div>
</div>
{% endif %}
<div class="row">
<div class="col text-right">
Source