NexusDashboard/app/luclient.py

440 lines
13 KiB
Python
Raw Normal View History

2022-01-16 18:22:00 +00:00
from flask import (
Blueprint,
send_file,
g,
redirect,
2022-05-12 01:37:22 +00:00
url_for,
make_response,
2022-12-17 07:15:27 +00:00
abort,
current_app
2022-01-16 18:22:00 +00:00
)
from flask_user import login_required
from app.models import CharacterInfo
import glob
import os
from wand import image
from wand.exceptions import BlobError as BE
import pathlib
2022-05-12 01:37:22 +00:00
import json
2022-01-16 18:22:00 +00:00
import sqlite3
import xml.etree.ElementTree as ET
luclient_blueprint = Blueprint('luclient', __name__)
locale = {}
2022-03-13 02:09:35 +00:00
2022-01-16 18:22:00 +00:00
@luclient_blueprint.route('/get_dds_as_png/<filename>')
@login_required
def get_dds_as_png(filename):
if filename.split('.')[-1] != 'dds':
return (404, "NO")
cache = f'cache/{filename.split(".")[0]}.png'
if not os.path.exists(cache):
2022-12-17 07:15:27 +00:00
root = f"{current_app.config['CLIENT_LOCATION']}res/"
2022-01-16 18:22:00 +00:00
path = glob.glob(
root + f'**/{filename}',
recursive=True
)[0]
with image.Image(filename=path) as img:
img.compression = "no"
img.save(filename=current_app.config["CACHE_LOCATION"] + filename.split('.')[0] + '.png')
2022-01-16 18:22:00 +00:00
return send_file(cache)
@luclient_blueprint.route('/get_dds/<filename>')
@login_required
def get_dds(filename):
if filename.split('.')[-1] != 'dds':
return 404
2022-12-17 07:15:27 +00:00
root = f"{current_app.config['CLIENT_LOCATION']}res/"
2022-01-16 18:22:00 +00:00
dds = glob.glob(
root + f'**/{filename}',
recursive=True
)[0]
return send_file(dds)
@luclient_blueprint.route('/get_icon_lot/<id>')
@login_required
def get_icon_lot(id):
2022-12-17 06:59:47 +00:00
if id is None:
redirect(url_for('luclient.unknown'))
2022-01-16 18:22:00 +00:00
render_component_id = query_cdclient(
'select component_id from ComponentsRegistry where component_type = 2 and id = ?',
[id],
one=True
2022-12-17 06:59:47 +00:00
)
if render_component_id is not None:
render_component_id = render_component_id[0]
else:
return redirect(url_for('luclient.unknown'))
2022-01-16 18:22:00 +00:00
# find the asset from rendercomponent given the component id
2022-03-13 02:09:35 +00:00
filename = query_cdclient(
'select icon_asset from RenderComponent where id = ?',
2022-01-16 18:22:00 +00:00
[render_component_id],
one=True
)[0]
2022-04-03 16:35:53 +00:00
if filename:
filename = filename.replace("..\\", "").replace("\\", "/")
else:
return redirect(url_for('luclient.unknown'))
2022-01-16 18:22:00 +00:00
cache = f'{current_app.config["CACHE_LOCATION"]}{filename.split(".")[0]}.png'
2022-01-16 18:22:00 +00:00
if not os.path.exists(cache):
2022-12-17 07:15:27 +00:00
root = f"{current_app.config['CLIENT_LOCATION']}res/"
2022-01-16 18:22:00 +00:00
try:
pathlib.Path(os.path.dirname(cache)).resolve().mkdir(parents=True, exist_ok=True)
2022-01-16 18:22:00 +00:00
with image.Image(filename=f'{root}{filename}'.lower()) as img:
img.compression = "no"
img.save(filename=cache)
2022-01-16 18:22:00 +00:00
except BE:
return redirect(url_for('luclient.unknown'))
return send_file(pathlib.Path(cache).resolve())
2022-01-16 18:22:00 +00:00
@luclient_blueprint.route('/get_icon_iconid/<id>')
@login_required
def get_icon_iconid(id):
filename = query_cdclient(
'select IconPath from Icons where IconID = ?',
[id],
one=True
)[0]
filename = filename.replace("..\\", "").replace("\\", "/")
cache = f'{current_app.config["CACHE_LOCATION"]}{filename.split(".")[0]}.png'
2022-01-16 18:22:00 +00:00
if not os.path.exists(cache):
2022-12-17 07:15:27 +00:00
root = f"{current_app.config['CLIENT_LOCATION']}res/"
2022-01-16 18:22:00 +00:00
try:
pathlib.Path(os.path.dirname(cache)).resolve().mkdir(parents=True, exist_ok=True)
2022-01-16 18:22:00 +00:00
with image.Image(filename=f'{root}{filename}'.lower()) as img:
img.compression = "no"
img.save(filename=cache)
2022-01-16 18:22:00 +00:00
except BE:
return redirect(url_for('luclient.unknown'))
return send_file(pathlib.Path(cache).resolve())
2022-01-16 18:22:00 +00:00
2022-03-13 02:09:35 +00:00
2022-05-12 01:37:22 +00:00
@luclient_blueprint.route('/ldddb/')
@login_required
def brick_list():
brick_list = []
if len(brick_list) == 0:
suffixes = [".g", ".g1", ".g2", ".g3", ".xml"]
2022-12-17 07:15:27 +00:00
res = pathlib.Path(f"{current_app.config['CLIENT_LOCATION']}res/")
2022-05-12 01:37:22 +00:00
# Load g files
for path in res.rglob("*.*"):
if str(path.suffix) in suffixes:
brick_list.append(
{
"type": "file",
2022-12-17 07:15:27 +00:00
"name": str(path.as_posix()).replace("{current_app.config['CLIENT_LOCATION']}res/", "")
2022-05-12 01:37:22 +00:00
}
)
response = make_response(json.dumps(brick_list))
response.headers.set('Content-Type', 'application/json')
return response
2022-05-12 02:33:31 +00:00
@luclient_blueprint.route('/ldddb/', defaults={'req_path': ''})
@luclient_blueprint.route('/ldddb/<path:req_path>')
def dir_listing(req_path):
2022-05-12 01:37:22 +00:00
# Joining the base and the requested path
2022-12-17 07:15:27 +00:00
rel_path = pathlib.Path(str(pathlib.Path(f"{current_app.config['CLIENT_LOCATION']}res/{req_path}").resolve()))
2022-05-12 01:37:22 +00:00
# Return 404 if path doesn't exist
if not rel_path.exists():
return abort(404)
# Check if path is a file and serve
if rel_path.is_file():
return send_file(rel_path)
else:
return abort(404)
2022-01-16 18:22:00 +00:00
@luclient_blueprint.route('/unknown')
@login_required
def unknown():
filename = "textures/ui/inventory/unknown.dds"
cache = f'{current_app.config["CACHE_LOCATION"]}{filename.split(".")[0]}.png'
2022-01-16 18:22:00 +00:00
if not os.path.exists(cache):
2022-12-17 07:15:27 +00:00
root = f"{current_app.config['CLIENT_LOCATION']}res/"
try:
pathlib.Path(os.path.dirname(cache)).resolve().mkdir(parents=True, exist_ok=True)
with image.Image(filename=f'{root}{filename}'.lower()) as img:
img.compression = "no"
img.save(filename=cache)
except BE:
return redirect(url_for('luclient.unknown'))
2022-01-16 18:22:00 +00:00
return send_file(pathlib.Path(cache).resolve())
2022-01-16 18:22:00 +00:00
def get_cdclient():
"""Connect to CDClient from file system Relative Path
Args:
None
"""
cdclient = getattr(g, '_cdclient', None)
if cdclient is None:
2022-12-17 07:15:27 +00:00
path = pathlib.Path(f"{current_app.config['CD_SQLITE_LOCATION']}cdclient.sqlite")
if path.is_file():
2022-12-17 07:15:27 +00:00
cdclient = g._database = sqlite3.connect(f"{current_app.config['CD_SQLITE_LOCATION']}cdclient.sqlite")
return cdclient
2022-12-17 07:15:27 +00:00
path = pathlib.Path(f"{current_app.config['CD_SQLITE_LOCATION']}CDServer.sqlite")
if path.is_file():
2022-12-17 07:15:27 +00:00
cdclient = g._database = sqlite3.connect(f"{current_app.config['CD_SQLITE_LOCATION']}CDServer.sqlite")
return cdclient
2022-01-16 18:22:00 +00:00
return cdclient
def query_cdclient(query, args=(), one=False):
"""Run sql queries on CDClient
Args:
query (string) : SQL query
args (list) : List of args to place in query
one (bool) : Return only on result or all results
"""
cur = get_cdclient().execute(query, args)
rv = cur.fetchall()
cur.close()
return (rv[0] if rv else None) if one else rv
def translate_from_locale(trans_string):
"""Finds the string translation from locale.xml
Args:
trans_string (string) : ID to find translation
"""
if not trans_string:
return "INVALID STRING"
global locale
locale_data = ""
if not locale:
2022-12-17 07:15:27 +00:00
locale_path = f"{current_app.config['CLIENT_LOCATION']}locale/locale.xml"
2022-01-16 18:22:00 +00:00
with open(locale_path, 'r') as file:
locale_data = file.read()
locale_xml = ET.XML(locale_data)
for item in locale_xml.findall('.//phrase'):
translation = ""
for translation_item in item.findall('.//translation'):
if translation_item.attrib["locale"] == "en_US":
translation = translation_item.text
locale[item.attrib['id']] = translation
if trans_string in locale:
return locale[trans_string]
else:
return trans_string
2022-03-13 02:09:35 +00:00
2022-03-14 03:10:07 +00:00
def get_lot_name(lot_id):
if not lot_id:
return "Missing"
2022-03-14 03:10:07 +00:00
name = translate_from_locale(f'Objects_{lot_id}_name')
if name == f'Objects_{lot_id}_name':
intermed = query_cdclient(
'select * from Objects where id = ?',
[lot_id],
one=True
)
if intermed:
name = intermed[7] if (intermed[7] != "None" and intermed[7] != "" and intermed[7] is None) else intermed[1]
return name
2022-01-16 18:22:00 +00:00
def register_luclient_jinja_helpers(app):
@app.template_filter('get_zone_name')
def get_zone_name(zone_id):
if not zone_id:
return "Missing"
2022-01-16 18:22:00 +00:00
return translate_from_locale(f'ZoneTable_{zone_id}_DisplayDescription')
@app.template_filter('get_skill_desc')
def get_skill_desc(skill_id):
2022-03-13 02:09:35 +00:00
return translate_from_locale(
f'SkillBehavior_{skill_id}_descriptionUI'
).replace(
"%(DamageCombo)", "Damage Combo: "
).replace(
"%(AltCombo)", "<br/>Skeleton Combo: "
).replace(
"%(Description)", "<br/>"
).replace(
"%(ChargeUp)", "<br/>Charge-up: "
)
2022-01-16 18:22:00 +00:00
@app.template_filter('parse_lzid')
def parse_lzid(lzid):
if not lzid: return [1000, 1000, 1000]
2022-01-16 18:22:00 +00:00
return[
(int(lzid) & ((1 << 16) - 1)),
((int(lzid) >> 16) & ((1 << 16) - 1)),
((int(lzid) >> 32) & ((1 << 30) - 1))
]
@app.template_filter('parse_other_player_id')
def parse_other_player_id(other_player_id):
char_id = (int(other_player_id) & 0xFFFFFFFF)
character = CharacterInfo.query.filter(CharacterInfo.id == char_id).first()
if character:
return[character.id, character.name]
else:
return None
@app.template_filter('get_lot_name')
2022-03-14 03:10:07 +00:00
def jinja_get_lot_name(lot_id):
return get_lot_name(lot_id)
2022-01-16 18:22:00 +00:00
@app.template_filter('get_lot_rarity')
def get_lot_rarity(lot_id):
if not lot_id:
return "Missing"
2022-01-16 18:22:00 +00:00
render_component_id = query_cdclient(
2022-01-17 02:37:08 +00:00
'select component_id from ComponentsRegistry where component_type = 11 and id = ?',
2022-01-16 18:22:00 +00:00
[lot_id],
one=True
2022-06-09 04:09:14 +00:00
)
if render_component_id:
render_component_id = render_component_id[0]
2022-01-16 18:22:00 +00:00
2022-03-13 02:09:35 +00:00
rarity = query_cdclient(
'select rarity from ItemComponent where id = ?',
2022-01-16 18:22:00 +00:00
[render_component_id],
one=True
)
if rarity:
rarity = rarity[0]
return rarity
@app.template_filter('get_lot_desc')
def get_lot_desc(lot_id):
if not lot_id:
return "Missing"
2022-01-16 18:22:00 +00:00
desc = translate_from_locale(f'Objects_{lot_id}_description')
if desc == f'Objects_{lot_id}_description':
desc = query_cdclient(
'select description from Objects where id = ?',
[lot_id],
one=True
2022-02-20 03:48:36 +00:00
)
2022-01-16 18:22:00 +00:00
if desc in ("", None):
desc = None
2022-02-20 03:48:36 +00:00
else:
desc = desc[0]
if desc in ("", None):
desc = None
if desc:
2022-02-04 01:06:25 +00:00
desc = desc.replace('"', "&#8220;")
2022-01-16 18:22:00 +00:00
return desc
@app.template_filter('get_item_set')
def check_if_in_set(lot_id):
if not lot_id:
return None
2022-01-16 18:22:00 +00:00
item_set = query_cdclient(
'select * from ItemSets where itemIDs like ? or itemIDs like ? or itemIDs like ?',
[f'{lot_id}%', f'%, {lot_id}%', f'%,{lot_id}%'],
one=True
)
if item_set in ("", None):
return None
else:
return item_set
@app.template_filter('get_lot_stats')
def get_lot_stats(lot_id):
if not lot_id:
return None
2022-01-16 18:22:00 +00:00
stats = query_cdclient(
'SELECT imBonusUI, lifeBonusUI, armorBonusUI, skillID, skillIcon FROM SkillBehavior WHERE skillID IN (\
SELECT skillID FROM ObjectSkills WHERE objectTemplate=?\
)',
[lot_id]
)
return consolidate_stats(stats)
@app.template_filter('get_set_stats')
def get_set_stats(lot_id):
if not lot_id:
return "Missing"
2022-01-16 18:22:00 +00:00
stats = query_cdclient(
'SELECT imBonusUI, lifeBonusUI, armorBonusUI, skillID, skillIcon FROM SkillBehavior WHERE skillID IN (\
SELECT skillID FROM ItemSetSkills WHERE SkillSetID=?\
)',
[lot_id]
)
return consolidate_stats(stats)
@app.template_filter('query_cdclient')
def jinja_query_cdclient(query, items):
print(query, items)
return query_cdclient(
query,
items,
one=True
)[0]
@app.template_filter('lu_translate')
def lu_translate(to_translate):
return translate_from_locale(to_translate)
def consolidate_stats(stats):
if len(stats) > 1:
2022-03-13 02:09:35 +00:00
consolidated_stats = {"im": 0, "life": 0, "armor": 0, "skill": []}
2022-01-16 18:22:00 +00:00
for stat in stats:
if stat[0]:
consolidated_stats["im"] += stat[0]
if stat[1]:
consolidated_stats["life"] += stat[1]
if stat[2]:
consolidated_stats["armor"] += stat[2]
if stat[3]:
2022-03-13 02:09:35 +00:00
consolidated_stats["skill"].append([stat[3], stat[4]])
2022-01-16 18:22:00 +00:00
stats = consolidated_stats
elif len(stats) == 1:
stats = {
"im": stats[0][0] if stats[0][0] else 0,
"life": stats[0][1] if stats[0][1] else 0,
"armor": stats[0][2] if stats[0][2] else 0,
"skill": [[stats[0][3], stats[0][4]]] if stats[0][3] else None,
}
else:
stats = None
return stats