mirror of
https://github.com/DarkflameUniverse/NexusDashboard.git
synced 2024-11-09 11:48:20 +00:00
syntax/linting fixes
This commit is contained in:
parent
70742549b9
commit
5ce9ac85bc
@ -10,7 +10,7 @@ from app.forms import CustomUserManager
|
|||||||
from flask_user import user_registered, current_user, user_logged_in
|
from flask_user import user_registered, current_user, user_logged_in
|
||||||
from flask_wtf.csrf import CSRFProtect
|
from flask_wtf.csrf import CSRFProtect
|
||||||
from flask_apscheduler import APScheduler
|
from flask_apscheduler import APScheduler
|
||||||
from app.luclient import query_cdclient, register_luclient_jinja_helpers
|
from app.luclient import register_luclient_jinja_helpers
|
||||||
|
|
||||||
from app.commands import init_db, init_accounts, load_property, gen_image_cache, gen_model_cache
|
from app.commands import init_db, init_accounts, load_property, gen_image_cache, gen_model_cache
|
||||||
from app.models import Account, AccountInvitation, AuditLog
|
from app.models import Account, AccountInvitation, AuditLog
|
||||||
@ -40,13 +40,12 @@ def create_app():
|
|||||||
app.logger.info(
|
app.logger.info(
|
||||||
f"USERS::REGISTRATION User with ID {user.id} and name {user.username} Registered \
|
f"USERS::REGISTRATION User with ID {user.id} and name {user.username} Registered \
|
||||||
using Play Key ID {play_key_used.id} : {play_key_used.key_string}"
|
using Play Key ID {play_key_used.id} : {play_key_used.key_string}"
|
||||||
)
|
)
|
||||||
db.session.add(play_key_used)
|
db.session.add(play_key_used)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
else:
|
else:
|
||||||
app.logger.info(f"USERS::REGISTRATION User with ID {user.id} and name {user.username} Registered")
|
app.logger.info(f"USERS::REGISTRATION User with ID {user.id} and name {user.username} Registered")
|
||||||
|
|
||||||
|
|
||||||
@user_logged_in.connect_via(app)
|
@user_logged_in.connect_via(app)
|
||||||
def _after_login_hook(sender, user, **extra):
|
def _after_login_hook(sender, user, **extra):
|
||||||
app.logger.info(f"{user.username} Logged in")
|
app.logger.info(f"{user.username} Logged in")
|
||||||
@ -55,7 +54,7 @@ def create_app():
|
|||||||
@app.template_filter('ctime')
|
@app.template_filter('ctime')
|
||||||
def timectime(s):
|
def timectime(s):
|
||||||
if s:
|
if s:
|
||||||
return time.ctime(s) # or datetime.datetime.fromtimestamp(s)
|
return time.ctime(s) # or datetime.datetime.fromtimestamp(s)
|
||||||
else:
|
else:
|
||||||
return "Never"
|
return "Never"
|
||||||
|
|
||||||
@ -246,6 +245,7 @@ def gm_level(gm_level):
|
|||||||
return wrapper
|
return wrapper
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
def log_audit(message):
|
def log_audit(message):
|
||||||
AuditLog(
|
AuditLog(
|
||||||
account_id=current_user.id,
|
account_id=current_user.id,
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
from flask import render_template, Blueprint, redirect, url_for, request, abort, current_app, flash, current_app
|
from flask import render_template, Blueprint, redirect, url_for, request, current_app, flash
|
||||||
from flask_user import login_required, current_user
|
from flask_user import login_required, current_user
|
||||||
import json
|
|
||||||
from datatables import ColumnDT, DataTables
|
from datatables import ColumnDT, DataTables
|
||||||
import datetime
|
import datetime
|
||||||
import time
|
from app.models import Account, db
|
||||||
from app.models import Account, AccountInvitation, db
|
|
||||||
from app.schemas import AccountSchema
|
from app.schemas import AccountSchema
|
||||||
from app import gm_level, log_audit
|
from app import gm_level, log_audit
|
||||||
from app.forms import EditGMLevelForm
|
from app.forms import EditGMLevelForm
|
||||||
@ -13,6 +11,7 @@ accounts_blueprint = Blueprint('accounts', __name__)
|
|||||||
|
|
||||||
account_schema = AccountSchema()
|
account_schema = AccountSchema()
|
||||||
|
|
||||||
|
|
||||||
@accounts_blueprint.route('/', methods=['GET'])
|
@accounts_blueprint.route('/', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
@ -38,7 +37,7 @@ def edit_gm_level(id):
|
|||||||
if current_user.id == int(id):
|
if current_user.id == int(id):
|
||||||
flash("You cannot your own GM Level", "danger")
|
flash("You cannot your own GM Level", "danger")
|
||||||
return redirect(request.referrer if request.referrer else url_for("main.index"))
|
return redirect(request.referrer if request.referrer else url_for("main.index"))
|
||||||
account_data = Account.query.filter(Account.id==id).first()
|
account_data = Account.query.filter(Account.id == id).first()
|
||||||
if account_data.gm_level >= 8 and current_user.gm_level == 8:
|
if account_data.gm_level >= 8 and current_user.gm_level == 8:
|
||||||
flash("You cannot edit this user's GM Level", "warning")
|
flash("You cannot edit this user's GM Level", "warning")
|
||||||
return redirect(request.referrer if request.referrer else url_for("main.index"))
|
return redirect(request.referrer if request.referrer else url_for("main.index"))
|
||||||
@ -138,10 +137,10 @@ def get():
|
|||||||
View
|
View
|
||||||
</a>
|
</a>
|
||||||
"""
|
"""
|
||||||
# <a role="button" class="btn btn-danger btn btn-block"
|
# <a role="button" class="btn btn-danger btn btn-block"
|
||||||
# href='{url_for('acounts.delete', id=account["0"])}'>
|
# href='{url_for('acounts.delete', id=account["0"])}'>
|
||||||
# Delete
|
# Delete
|
||||||
# </a>
|
# </a>
|
||||||
|
|
||||||
if account["4"]:
|
if account["4"]:
|
||||||
account["4"] = '''<h2 class="far fa-times-circle text-danger"></h2>'''
|
account["4"] = '''<h2 class="far fa-times-circle text-danger"></h2>'''
|
||||||
@ -154,13 +153,13 @@ def get():
|
|||||||
account["5"] = '''<h2 class="far fa-check-square text-success"></h2>'''
|
account["5"] = '''<h2 class="far fa-check-square text-success"></h2>'''
|
||||||
|
|
||||||
if account["6"]:
|
if account["6"]:
|
||||||
account["6"] = f'''<h2 class="far fa-times-circle text-danger"></h2>'''
|
account["6"] = '''<h2 class="far fa-times-circle text-danger"></h2>'''
|
||||||
else:
|
else:
|
||||||
account["6"] = '''<h2 class="far fa-check-square text-success"></h2>'''
|
account["6"] = '''<h2 class="far fa-check-square text-success"></h2>'''
|
||||||
|
|
||||||
if current_app.config["USER_ENABLE_EMAIL"]:
|
if current_app.config["USER_ENABLE_EMAIL"]:
|
||||||
if account["8"]:
|
if account["8"]:
|
||||||
account["8"] = f'''<h2 class="far fa-check-square text-success"></h2>'''
|
account["8"] = '''<h2 class="far fa-check-square text-success"></h2>'''
|
||||||
else:
|
else:
|
||||||
account["8"] = '''<h2 class="far fa-times-circle text-danger"></h2>'''
|
account["8"] = '''<h2 class="far fa-times-circle text-danger"></h2>'''
|
||||||
else:
|
else:
|
||||||
@ -175,4 +174,3 @@ def get():
|
|||||||
del account["8"]
|
del account["8"]
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from flask import render_template, Blueprint, redirect, url_for, request, abort, flash
|
from flask import render_template, Blueprint, redirect, url_for, request, flash
|
||||||
from flask_user import login_required, current_user
|
from flask_user import login_required, current_user
|
||||||
from app.models import db, BugReport, CharacterInfo
|
from app.models import db, BugReport, CharacterInfo
|
||||||
from datatables import ColumnDT, DataTables
|
from datatables import ColumnDT, DataTables
|
||||||
@ -8,6 +8,7 @@ from app.luclient import translate_from_locale
|
|||||||
|
|
||||||
bug_report_blueprint = Blueprint('bug_reports', __name__)
|
bug_report_blueprint = Blueprint('bug_reports', __name__)
|
||||||
|
|
||||||
|
|
||||||
@bug_report_blueprint.route('/<status>', methods=['GET'])
|
@bug_report_blueprint.route('/<status>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
@ -23,7 +24,7 @@ def view(id):
|
|||||||
if report.resoleved_by:
|
if report.resoleved_by:
|
||||||
rb = report.resoleved_by.username
|
rb = report.resoleved_by.username
|
||||||
else:
|
else:
|
||||||
rb=""
|
rb = ""
|
||||||
return render_template('bug_reports/view.html.j2', report=report, resolved_by=rb)
|
return render_template('bug_reports/view.html.j2', report=report, resolved_by=rb)
|
||||||
|
|
||||||
|
|
||||||
@ -62,12 +63,12 @@ def get(status):
|
|||||||
]
|
]
|
||||||
|
|
||||||
query = None
|
query = None
|
||||||
if status=="all":
|
if status == "all":
|
||||||
query = db.session.query().select_from(BugReport)
|
query = db.session.query().select_from(BugReport)
|
||||||
elif status=="resolved":
|
elif status == "resolved":
|
||||||
query = db.session.query().select_from(BugReport).filter(BugReport.resolved_time != None)
|
query = db.session.query().select_from(BugReport).filter(BugReport.resolved_time not None)
|
||||||
elif status=="unresolved":
|
elif status == "unresolved":
|
||||||
query = db.session.query().select_from(BugReport).filter(BugReport.resolved_time == None)
|
query = db.session.query().select_from(BugReport).filter(BugReport.resolved_time is None)
|
||||||
else:
|
else:
|
||||||
raise Exception("Not a valid filter")
|
raise Exception("Not a valid filter")
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
from flask import render_template, Blueprint, redirect, url_for, request, abort, flash, make_response
|
from flask import render_template, Blueprint, redirect, url_for, request, abort, flash, make_response
|
||||||
from flask_user import login_required, current_user
|
from flask_user import login_required, current_user
|
||||||
import json
|
|
||||||
from datatables import ColumnDT, DataTables
|
from datatables import ColumnDT, DataTables
|
||||||
import datetime, time
|
import time
|
||||||
from app.models import CharacterInfo, CharacterXML, Account, db
|
from app.models import CharacterInfo, CharacterXML, Account, db
|
||||||
from app.schemas import CharacterInfoSchema
|
from app.schemas import CharacterInfoSchema
|
||||||
from app.forms import RescueForm
|
from app.forms import RescueForm
|
||||||
@ -16,6 +15,7 @@ character_blueprint = Blueprint('characters', __name__)
|
|||||||
|
|
||||||
character_schema = CharacterInfoSchema()
|
character_schema = CharacterInfoSchema()
|
||||||
|
|
||||||
|
|
||||||
@character_blueprint.route('/', methods=['GET'])
|
@character_blueprint.route('/', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
@ -27,7 +27,7 @@ def index():
|
|||||||
@login_required
|
@login_required
|
||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
def approve_name(id, action):
|
def approve_name(id, action):
|
||||||
character = CharacterInfo.query.filter(CharacterInfo.id == id).first()
|
character = CharacterInfo.query.filter(CharacterInfo.id == id).first()
|
||||||
|
|
||||||
if action == "approve":
|
if action == "approve":
|
||||||
log_audit(f"Approved ({character.id}){character.pending_name} from {character.name}")
|
log_audit(f"Approved ({character.id}){character.pending_name} from {character.name}")
|
||||||
@ -42,9 +42,12 @@ def approve_name(id, action):
|
|||||||
|
|
||||||
elif action == "rename":
|
elif action == "rename":
|
||||||
character.needs_rename = True
|
character.needs_rename = True
|
||||||
log_audit(f"Marked character ({character.id}){character.name} (Pending Name: {character.pending_name if character.pending_name else 'None'}) as needing Rename")
|
log_audit(
|
||||||
|
f"Marked character ({character.id}){character.name} \
|
||||||
|
(Pending Name: {character.pending_name if character.pending_name else 'None'}) as needing Rename")
|
||||||
flash(
|
flash(
|
||||||
f"Marked character {character.name} (Pending Name: {character.pending_name if character.pending_name else 'None'}) as needing Rename",
|
f"Marked character {character.name} \
|
||||||
|
(Pending Name: {character.pending_name if character.pending_name else 'None'}) as needing Rename",
|
||||||
"danger"
|
"danger"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -67,11 +70,11 @@ def view(id):
|
|||||||
abort(403)
|
abort(403)
|
||||||
return
|
return
|
||||||
character_json = xmltodict.parse(
|
character_json = xmltodict.parse(
|
||||||
CharacterXML.query.filter(
|
CharacterXML.query.filter(
|
||||||
CharacterXML.id==id
|
CharacterXML.id == id
|
||||||
).first().xml_data,
|
).first().xml_data,
|
||||||
attr_prefix="attr_"
|
attr_prefix="attr_"
|
||||||
)
|
)
|
||||||
|
|
||||||
# print json for reference
|
# print json for reference
|
||||||
# with open("errorchar.json", "a") as file:
|
# with open("errorchar.json", "a") as file:
|
||||||
@ -84,8 +87,7 @@ def view(id):
|
|||||||
# sort by items slot index
|
# sort by items slot index
|
||||||
for inv in character_json["obj"]["inv"]["holdings"]["in"]:
|
for inv in character_json["obj"]["inv"]["holdings"]["in"]:
|
||||||
if "i" in inv.keys() and type(inv["i"]) == list:
|
if "i" in inv.keys() and type(inv["i"]) == list:
|
||||||
inv["i"] = sorted(inv["i"], key = lambda i: int(i['attr_s']))
|
inv["i"] = sorted(inv["i"], key=lambda i: int(i['attr_s']))
|
||||||
|
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'character/view.html.j2',
|
'character/view.html.j2',
|
||||||
@ -110,13 +112,14 @@ def view_xml(id):
|
|||||||
return
|
return
|
||||||
|
|
||||||
character_xml = CharacterXML.query.filter(
|
character_xml = CharacterXML.query.filter(
|
||||||
CharacterXML.id==id
|
CharacterXML.id == id
|
||||||
).first().xml_data
|
).first().xml_data
|
||||||
|
|
||||||
response = make_response(character_xml)
|
response = make_response(character_xml)
|
||||||
response.headers.set('Content-Type', 'text/xml')
|
response.headers.set('Content-Type', 'text/xml')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
@character_blueprint.route('/get_xml/<id>', methods=['GET'])
|
@character_blueprint.route('/get_xml/<id>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def get_xml(id):
|
def get_xml(id):
|
||||||
@ -132,8 +135,8 @@ def get_xml(id):
|
|||||||
return
|
return
|
||||||
|
|
||||||
character_xml = CharacterXML.query.filter(
|
character_xml = CharacterXML.query.filter(
|
||||||
CharacterXML.id==id
|
CharacterXML.id == id
|
||||||
).first().xml_data
|
).first().xml_data
|
||||||
|
|
||||||
response = make_response(character_xml)
|
response = make_response(character_xml)
|
||||||
response.headers.set('Content-Type', 'attachment/xml')
|
response.headers.set('Content-Type', 'attachment/xml')
|
||||||
@ -144,6 +147,7 @@ def get_xml(id):
|
|||||||
)
|
)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
@character_blueprint.route('/restrict/<bit>/<id>', methods=['GET'])
|
@character_blueprint.route('/restrict/<bit>/<id>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
@ -177,8 +181,8 @@ def rescue(id):
|
|||||||
form = RescueForm()
|
form = RescueForm()
|
||||||
|
|
||||||
character_data = CharacterXML.query.filter(
|
character_data = CharacterXML.query.filter(
|
||||||
CharacterXML.id==id
|
CharacterXML.id == id
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
character_xml = ET.XML(character_data.xml_data)
|
character_xml = ET.XML(character_data.xml_data)
|
||||||
for zone in character_xml.findall('.//r'):
|
for zone in character_xml.findall('.//r'):
|
||||||
@ -205,6 +209,7 @@ def rescue(id):
|
|||||||
|
|
||||||
return render_template("character/rescue.html.j2", form=form)
|
return render_template("character/rescue.html.j2", form=form)
|
||||||
|
|
||||||
|
|
||||||
@character_blueprint.route('/get/<status>', methods=['GET'])
|
@character_blueprint.route('/get/<status>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
@ -220,12 +225,12 @@ def get(status):
|
|||||||
]
|
]
|
||||||
|
|
||||||
query = None
|
query = None
|
||||||
if status=="all":
|
if status == "all":
|
||||||
query = db.session.query().select_from(CharacterInfo).join(Account)
|
query = db.session.query().select_from(CharacterInfo).join(Account)
|
||||||
elif status=="approved":
|
elif status == "approved":
|
||||||
query = db.session.query().select_from(CharacterInfo).join(Account).filter((CharacterInfo.pending_name == "") & (CharacterInfo.needs_rename == False))
|
query = db.session.query().select_from(CharacterInfo).join(Account).filter((CharacterInfo.pending_name == "") & (CharacterInfo.needs_rename is False))
|
||||||
elif status=="unapproved":
|
elif status == "unapproved":
|
||||||
query = db.session.query().select_from(CharacterInfo).join(Account).filter((CharacterInfo.pending_name != "") | (CharacterInfo.needs_rename == True))
|
query = db.session.query().select_from(CharacterInfo).join(Account).filter((CharacterInfo.pending_name != "") | (CharacterInfo.needs_rename is True))
|
||||||
else:
|
else:
|
||||||
raise Exception("Not a valid filter")
|
raise Exception("Not a valid filter")
|
||||||
|
|
||||||
@ -286,6 +291,4 @@ def get(status):
|
|||||||
if perm_map & (1 << 6):
|
if perm_map & (1 << 6):
|
||||||
character["6"] += "Restricted Chat</br>"
|
character["6"] += "Restricted Chat</br>"
|
||||||
|
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
import click
|
import click
|
||||||
import json
|
|
||||||
from flask.cli import with_appcontext
|
from flask.cli import with_appcontext
|
||||||
import random, string, datetime
|
import random
|
||||||
|
import string
|
||||||
|
import datetime
|
||||||
from flask_user import current_app
|
from flask_user import current_app
|
||||||
from app import db
|
from app import db
|
||||||
from app.models import Account, PlayKey, CharacterInfo, Property, PropertyContent, UGC
|
from app.models import Account, PlayKey, CharacterInfo, Property, PropertyContent, UGC
|
||||||
import pathlib
|
import pathlib
|
||||||
import zlib
|
import zlib
|
||||||
import os
|
|
||||||
from wand import image
|
from wand import image
|
||||||
from wand.exceptions import BlobError as BE
|
from wand.exceptions import BlobError as BE
|
||||||
import app.pylddlib as ldd
|
import app.pylddlib as ldd
|
||||||
from multiprocessing import Pool
|
from multiprocessing import Pool
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
|
|
||||||
@click.command("init_db")
|
@click.command("init_db")
|
||||||
@click.argument('drop_tables', nargs=1)
|
@click.argument('drop_tables', nargs=1)
|
||||||
@with_appcontext
|
@with_appcontext
|
||||||
@ -45,6 +46,7 @@ def init_accounts():
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
@click.command("load_property")
|
@click.command("load_property")
|
||||||
@click.argument('zone')
|
@click.argument('zone')
|
||||||
@click.argument('player')
|
@click.argument('player')
|
||||||
@ -56,7 +58,7 @@ def load_property(zone, player):
|
|||||||
print("Character not Found")
|
print("Character not Found")
|
||||||
return 404
|
return 404
|
||||||
|
|
||||||
prop = Property.query.filter(Property.owner_id==char.id).filter(Property.zone_id==zone).first()
|
prop = Property.query.filter(Property.owner_id == char.id).filter(Property.zone_id == zone).first()
|
||||||
|
|
||||||
if not prop:
|
if not prop:
|
||||||
print(f"Property {zone} not claimed by Character: {char.name}")
|
print(f"Property {zone} not claimed by Character: {char.name}")
|
||||||
@ -95,6 +97,7 @@ def load_property(zone, player):
|
|||||||
)
|
)
|
||||||
new_prop_content.save()
|
new_prop_content.save()
|
||||||
|
|
||||||
|
|
||||||
@click.command("gen_image_cache")
|
@click.command("gen_image_cache")
|
||||||
def gen_image_cache():
|
def gen_image_cache():
|
||||||
"""generates image cache"""
|
"""generates image cache"""
|
||||||
@ -113,6 +116,7 @@ def gen_image_cache():
|
|||||||
except BE:
|
except BE:
|
||||||
return print(f"Error on {file}")
|
return print(f"Error on {file}")
|
||||||
|
|
||||||
|
|
||||||
@click.command("gen_model_cache")
|
@click.command("gen_model_cache")
|
||||||
def gen_model_cache():
|
def gen_model_cache():
|
||||||
"""generate model obj cache"""
|
"""generate model obj cache"""
|
||||||
@ -123,19 +127,21 @@ def gen_model_cache():
|
|||||||
pool.map(partial(convert_lxfml_to_obj, lod=1), files)
|
pool.map(partial(convert_lxfml_to_obj, lod=1), files)
|
||||||
pool.map(partial(convert_lxfml_to_obj, lod=2), files)
|
pool.map(partial(convert_lxfml_to_obj, lod=2), files)
|
||||||
|
|
||||||
|
|
||||||
def convert_lxfml_to_obj(file, lod):
|
def convert_lxfml_to_obj(file, lod):
|
||||||
mtl = get_cache_file(file).with_suffix(f".lod{lod}.mtl")
|
mtl = get_cache_file(file).with_suffix(f".lod{lod}.mtl")
|
||||||
if not mtl.exists():
|
if not mtl.exists():
|
||||||
mtl.parent.mkdir(parents=True, exist_ok=True)
|
mtl.parent.mkdir(parents=True, exist_ok=True)
|
||||||
print(f"Convert LXFML {file.as_posix()} to obj and mtl @ {mtl}")
|
print(f"Convert LXFML {file.as_posix()} to obj and mtl @ {mtl}")
|
||||||
try:
|
try:
|
||||||
ldd.main(str(file.as_posix()), str(mtl.with_suffix("").as_posix()), lod) # convert to OBJ
|
ldd.main(str(file.as_posix()), str(mtl.with_suffix("").as_posix()), lod) # convert to OBJ
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"ERROR on {file}:\n {e}")
|
print(f"ERROR on {file}:\n {e}")
|
||||||
else:
|
else:
|
||||||
# print(f"Already Exists: {file} with LOD {lod}")
|
# print(f"Already Exists: {file} with LOD {lod}")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def get_cache_file(path):
|
def get_cache_file(path):
|
||||||
"""helper"""
|
"""helper"""
|
||||||
# convert to list so that we can change elements
|
# convert to list so that we can change elements
|
||||||
@ -147,6 +153,7 @@ def get_cache_file(path):
|
|||||||
|
|
||||||
return pathlib.Path(*parts)
|
return pathlib.Path(*parts)
|
||||||
|
|
||||||
|
|
||||||
def find_or_create_account(name, email, password, gm_level=9):
|
def find_or_create_account(name, email, password, gm_level=9):
|
||||||
""" Find existing account or create new account """
|
""" Find existing account or create new account """
|
||||||
account = Account.query.filter(Account.email == email).first()
|
account = Account.query.filter(Account.email == email).first()
|
||||||
@ -164,15 +171,16 @@ def find_or_create_account(name, email, password, gm_level=9):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
play_key = PlayKey.query.filter(PlayKey.key_string == key).first()
|
play_key = PlayKey.query.filter(PlayKey.key_string == key).first()
|
||||||
account = Account(email=email,
|
account = Account(
|
||||||
username=name,
|
email=email,
|
||||||
password=current_app.user_manager.password_manager.hash_password(password),
|
username=name,
|
||||||
play_key_id=play_key.id,
|
password=current_app.user_manager.password_manager.hash_password(password),
|
||||||
email_confirmed_at=datetime.datetime.utcnow(),
|
play_key_id=play_key.id,
|
||||||
gm_level=gm_level
|
email_confirmed_at=datetime.datetime.utcnow(),
|
||||||
)
|
gm_level=gm_level
|
||||||
|
)
|
||||||
play_key.key_uses = 0
|
play_key.key_uses = 0
|
||||||
db.session.add(account)
|
db.session.add(account)
|
||||||
db.session.add(play_key)
|
db.session.add(play_key)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return # account
|
return # account
|
||||||
|
14
app/forms.py
14
app/forms.py
@ -16,13 +16,13 @@ from wtforms import (
|
|||||||
SubmitField,
|
SubmitField,
|
||||||
validators,
|
validators,
|
||||||
IntegerField,
|
IntegerField,
|
||||||
StringField,
|
|
||||||
SelectField
|
SelectField
|
||||||
)
|
)
|
||||||
|
|
||||||
from wtforms.validators import DataRequired, Optional
|
from wtforms.validators import DataRequired, Optional
|
||||||
from app.models import PlayKey
|
from app.models import PlayKey
|
||||||
|
|
||||||
|
|
||||||
def validate_play_key(form, field):
|
def validate_play_key(form, field):
|
||||||
"""Validates a field for a valid phone number
|
"""Validates a field for a valid phone number
|
||||||
Args:
|
Args:
|
||||||
@ -85,6 +85,7 @@ class CustomRegisterForm(FlaskForm):
|
|||||||
|
|
||||||
submit = SubmitField('Register')
|
submit = SubmitField('Register')
|
||||||
|
|
||||||
|
|
||||||
class CreatePlayKeyForm(FlaskForm):
|
class CreatePlayKeyForm(FlaskForm):
|
||||||
|
|
||||||
count = IntegerField(
|
count = IntegerField(
|
||||||
@ -97,6 +98,7 @@ class CreatePlayKeyForm(FlaskForm):
|
|||||||
)
|
)
|
||||||
submit = SubmitField('Create!')
|
submit = SubmitField('Create!')
|
||||||
|
|
||||||
|
|
||||||
class EditPlayKeyForm(FlaskForm):
|
class EditPlayKeyForm(FlaskForm):
|
||||||
|
|
||||||
active = BooleanField(
|
active = BooleanField(
|
||||||
@ -119,7 +121,7 @@ class EditGMLevelForm(FlaskForm):
|
|||||||
|
|
||||||
gm_level = IntegerField(
|
gm_level = IntegerField(
|
||||||
'GM Level',
|
'GM Level',
|
||||||
widget=NumberInput(min = 0, max = 9)
|
widget=NumberInput(min=0, max=9)
|
||||||
)
|
)
|
||||||
|
|
||||||
submit = SubmitField('Submit')
|
submit = SubmitField('Submit')
|
||||||
@ -142,8 +144,8 @@ class SendMailForm(FlaskForm):
|
|||||||
'Recipient: ',
|
'Recipient: ',
|
||||||
coerce=str,
|
coerce=str,
|
||||||
choices=[
|
choices=[
|
||||||
("",""),
|
("", ""),
|
||||||
("0","All Characters"),
|
("0", "All Characters"),
|
||||||
],
|
],
|
||||||
validators=[validators.DataRequired()]
|
validators=[validators.DataRequired()]
|
||||||
)
|
)
|
||||||
@ -162,7 +164,7 @@ class SendMailForm(FlaskForm):
|
|||||||
attachment = SelectField(
|
attachment = SelectField(
|
||||||
"Attachment",
|
"Attachment",
|
||||||
coerce=str,
|
coerce=str,
|
||||||
choices=[(0,"No Attachment")]
|
choices=[(0, "No Attachment")]
|
||||||
)
|
)
|
||||||
|
|
||||||
attachment_count = IntegerField(
|
attachment_count = IntegerField(
|
||||||
@ -179,7 +181,7 @@ class RescueForm(FlaskForm):
|
|||||||
'Move to:',
|
'Move to:',
|
||||||
coerce=str,
|
coerce=str,
|
||||||
choices=[
|
choices=[
|
||||||
("",""),
|
("", ""),
|
||||||
],
|
],
|
||||||
validators=[validators.DataRequired()]
|
validators=[validators.DataRequired()]
|
||||||
)
|
)
|
||||||
|
19
app/log.py
19
app/log.py
@ -1,5 +1,5 @@
|
|||||||
from flask import render_template, Blueprint, request, url_for
|
from flask import render_template, Blueprint, request, url_for
|
||||||
from flask_user import login_required, current_user
|
from flask_user import login_required
|
||||||
from app.models import CommandLog, ActivityLog, db, Account, CharacterInfo, AuditLog
|
from app.models import CommandLog, ActivityLog, db, Account, CharacterInfo, AuditLog
|
||||||
from datatables import ColumnDT, DataTables
|
from datatables import ColumnDT, DataTables
|
||||||
import time
|
import time
|
||||||
@ -7,6 +7,7 @@ from app import gm_level
|
|||||||
|
|
||||||
log_blueprint = Blueprint('log', __name__)
|
log_blueprint = Blueprint('log', __name__)
|
||||||
|
|
||||||
|
|
||||||
@log_blueprint.route('/activities', methods=['GET'])
|
@log_blueprint.route('/activities', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@gm_level(8)
|
@gm_level(8)
|
||||||
@ -40,11 +41,11 @@ def audit():
|
|||||||
@gm_level(8)
|
@gm_level(8)
|
||||||
def get_activities():
|
def get_activities():
|
||||||
columns = [
|
columns = [
|
||||||
ColumnDT(ActivityLog.id), # 0
|
ColumnDT(ActivityLog.id), # 0
|
||||||
ColumnDT(ActivityLog.character_id), # 1
|
ColumnDT(ActivityLog.character_id), # 1
|
||||||
ColumnDT(ActivityLog.activity), # 2
|
ColumnDT(ActivityLog.activity), # 2
|
||||||
ColumnDT(ActivityLog.time), # 3
|
ColumnDT(ActivityLog.time), # 3
|
||||||
ColumnDT(ActivityLog.map_id), # 4
|
ColumnDT(ActivityLog.map_id), # 4
|
||||||
]
|
]
|
||||||
|
|
||||||
query = db.session.query().select_from(ActivityLog)
|
query = db.session.query().select_from(ActivityLog)
|
||||||
@ -82,9 +83,9 @@ def get_activities():
|
|||||||
@gm_level(8)
|
@gm_level(8)
|
||||||
def get_commands():
|
def get_commands():
|
||||||
columns = [
|
columns = [
|
||||||
ColumnDT(CommandLog.id), # 0
|
ColumnDT(CommandLog.id), # 0
|
||||||
ColumnDT(CommandLog.character_id), # 1
|
ColumnDT(CommandLog.character_id), # 1
|
||||||
ColumnDT(CommandLog.command), # 2
|
ColumnDT(CommandLog.command), # 2
|
||||||
]
|
]
|
||||||
|
|
||||||
query = db.session.query().select_from(CommandLog)
|
query = db.session.query().select_from(CommandLog)
|
||||||
|
@ -19,6 +19,7 @@ import xml.etree.ElementTree as ET
|
|||||||
luclient_blueprint = Blueprint('luclient', __name__)
|
luclient_blueprint = Blueprint('luclient', __name__)
|
||||||
locale = {}
|
locale = {}
|
||||||
|
|
||||||
|
|
||||||
@luclient_blueprint.route('/get_dds_as_png/<filename>')
|
@luclient_blueprint.route('/get_dds_as_png/<filename>')
|
||||||
@login_required
|
@login_required
|
||||||
def get_dds_as_png(filename):
|
def get_dds_as_png(filename):
|
||||||
@ -37,7 +38,7 @@ def get_dds_as_png(filename):
|
|||||||
|
|
||||||
with image.Image(filename=path) as img:
|
with image.Image(filename=path) as img:
|
||||||
img.compression = "no"
|
img.compression = "no"
|
||||||
img.save(filename='app/cache/'+filename.split('.')[0] + '.png')
|
img.save(filename='app/cache/' + filename.split('.')[0] + '.png')
|
||||||
|
|
||||||
return send_file(cache)
|
return send_file(cache)
|
||||||
|
|
||||||
@ -69,7 +70,8 @@ def get_icon_lot(id):
|
|||||||
)[0]
|
)[0]
|
||||||
|
|
||||||
# find the asset from rendercomponent given the component id
|
# find the asset from rendercomponent given the component id
|
||||||
filename = query_cdclient('select icon_asset from RenderComponent where id = ?',
|
filename = query_cdclient(
|
||||||
|
'select icon_asset from RenderComponent where id = ?',
|
||||||
[render_component_id],
|
[render_component_id],
|
||||||
one=True
|
one=True
|
||||||
)[0]
|
)[0]
|
||||||
@ -117,6 +119,7 @@ def get_icon_iconid(id):
|
|||||||
|
|
||||||
return send_file(pathlib.Path(cache).resolve())
|
return send_file(pathlib.Path(cache).resolve())
|
||||||
|
|
||||||
|
|
||||||
@luclient_blueprint.route('/unknown')
|
@luclient_blueprint.route('/unknown')
|
||||||
@login_required
|
@login_required
|
||||||
def unknown():
|
def unknown():
|
||||||
@ -195,6 +198,7 @@ def translate_from_locale(trans_string):
|
|||||||
else:
|
else:
|
||||||
return trans_string
|
return trans_string
|
||||||
|
|
||||||
|
|
||||||
def register_luclient_jinja_helpers(app):
|
def register_luclient_jinja_helpers(app):
|
||||||
|
|
||||||
@app.template_filter('get_zone_name')
|
@app.template_filter('get_zone_name')
|
||||||
@ -203,15 +207,17 @@ def register_luclient_jinja_helpers(app):
|
|||||||
|
|
||||||
@app.template_filter('get_skill_desc')
|
@app.template_filter('get_skill_desc')
|
||||||
def get_skill_desc(skill_id):
|
def get_skill_desc(skill_id):
|
||||||
return translate_from_locale(f'SkillBehavior_{skill_id}_descriptionUI').replace(
|
return translate_from_locale(
|
||||||
"%(DamageCombo)", "Damage Combo: "
|
f'SkillBehavior_{skill_id}_descriptionUI'
|
||||||
).replace(
|
).replace(
|
||||||
"%(AltCombo)", "<br/>Skeleton Combo: "
|
"%(DamageCombo)", "Damage Combo: "
|
||||||
).replace(
|
).replace(
|
||||||
"%(Description)", "<br/>"
|
"%(AltCombo)", "<br/>Skeleton Combo: "
|
||||||
).replace(
|
).replace(
|
||||||
"%(ChargeUp)", "<br/>Charge-up: "
|
"%(Description)", "<br/>"
|
||||||
)
|
).replace(
|
||||||
|
"%(ChargeUp)", "<br/>Charge-up: "
|
||||||
|
)
|
||||||
|
|
||||||
@app.template_filter('parse_lzid')
|
@app.template_filter('parse_lzid')
|
||||||
def parse_lzid(lzid):
|
def parse_lzid(lzid):
|
||||||
@ -240,7 +246,7 @@ def register_luclient_jinja_helpers(app):
|
|||||||
one=True
|
one=True
|
||||||
)
|
)
|
||||||
if intermed:
|
if intermed:
|
||||||
name = intermed[7] if (intermed[7] != "None" and intermed[7] !="" and intermed[7] != None) else intermed[1]
|
name = intermed[7] if (intermed[7] != "None" and intermed[7] != "" and intermed[7] is None) else intermed[1]
|
||||||
return name
|
return name
|
||||||
|
|
||||||
@app.template_filter('get_lot_rarity')
|
@app.template_filter('get_lot_rarity')
|
||||||
@ -252,7 +258,8 @@ def register_luclient_jinja_helpers(app):
|
|||||||
one=True
|
one=True
|
||||||
)[0]
|
)[0]
|
||||||
|
|
||||||
rarity = query_cdclient('select rarity from ItemComponent where id = ?',
|
rarity = query_cdclient(
|
||||||
|
'select rarity from ItemComponent where id = ?',
|
||||||
[render_component_id],
|
[render_component_id],
|
||||||
one=True
|
one=True
|
||||||
)
|
)
|
||||||
@ -302,7 +309,6 @@ def register_luclient_jinja_helpers(app):
|
|||||||
|
|
||||||
return consolidate_stats(stats)
|
return consolidate_stats(stats)
|
||||||
|
|
||||||
|
|
||||||
@app.template_filter('get_set_stats')
|
@app.template_filter('get_set_stats')
|
||||||
def get_set_stats(lot_id):
|
def get_set_stats(lot_id):
|
||||||
stats = query_cdclient(
|
stats = query_cdclient(
|
||||||
@ -331,7 +337,7 @@ def register_luclient_jinja_helpers(app):
|
|||||||
def consolidate_stats(stats):
|
def consolidate_stats(stats):
|
||||||
|
|
||||||
if len(stats) > 1:
|
if len(stats) > 1:
|
||||||
consolidated_stats = {"im": 0,"life": 0,"armor": 0, "skill": []}
|
consolidated_stats = {"im": 0, "life": 0, "armor": 0, "skill": []}
|
||||||
for stat in stats:
|
for stat in stats:
|
||||||
if stat[0]:
|
if stat[0]:
|
||||||
consolidated_stats["im"] += stat[0]
|
consolidated_stats["im"] += stat[0]
|
||||||
@ -340,8 +346,7 @@ def consolidate_stats(stats):
|
|||||||
if stat[2]:
|
if stat[2]:
|
||||||
consolidated_stats["armor"] += stat[2]
|
consolidated_stats["armor"] += stat[2]
|
||||||
if stat[3]:
|
if stat[3]:
|
||||||
consolidated_stats["skill"].append([stat[3],stat[4]])
|
consolidated_stats["skill"].append([stat[3], stat[4]])
|
||||||
|
|
||||||
|
|
||||||
stats = consolidated_stats
|
stats = consolidated_stats
|
||||||
elif len(stats) == 1:
|
elif len(stats) == 1:
|
||||||
|
56
app/mail.py
56
app/mail.py
@ -1,7 +1,6 @@
|
|||||||
from flask import render_template, Blueprint, redirect, url_for, request, abort, flash, request
|
from flask import render_template, Blueprint, redirect, url_for, flash, request
|
||||||
from flask_user import login_required, current_user
|
from flask_user import login_required, current_user
|
||||||
from app.models import db, Mail, CharacterInfo
|
from app.models import Mail, CharacterInfo
|
||||||
from datatables import ColumnDT, DataTables
|
|
||||||
from app.forms import SendMailForm
|
from app.forms import SendMailForm
|
||||||
from app import gm_level, log_audit
|
from app import gm_level, log_audit
|
||||||
from app.luclient import translate_from_locale, query_cdclient
|
from app.luclient import translate_from_locale, query_cdclient
|
||||||
@ -31,37 +30,40 @@ def send():
|
|||||||
log_audit(f"Sending {form.subject.data}: {form.body.data} to All Characters with {form.attachment_count.data} of item {form.attachment.data}")
|
log_audit(f"Sending {form.subject.data}: {form.body.data} to All Characters with {form.attachment_count.data} of item {form.attachment.data}")
|
||||||
for character in CharacterInfo.query.all():
|
for character in CharacterInfo.query.all():
|
||||||
Mail(
|
Mail(
|
||||||
sender_id = 0,
|
sender_id=0,
|
||||||
sender_name = f"[GM] {current_user.username}",
|
sender_name=f"[GM] {current_user.username}",
|
||||||
receiver_id = character.id,
|
receiver_id=character.id,
|
||||||
receiver_name = character.name,
|
receiver_name=character.name,
|
||||||
time_sent = time.time(),
|
time_sent=time.time(),
|
||||||
subject = form.subject.data,
|
subject=form.subject.data,
|
||||||
body = form.body.data,
|
body=form.body.data,
|
||||||
attachment_id = 0,
|
attachment_id=0,
|
||||||
attachment_lot = form.attachment.data,
|
attachment_lot=form.attachment.data,
|
||||||
attachment_count = form.attachment_count.data
|
attachment_count=form.attachment_count.data
|
||||||
).save()
|
).save()
|
||||||
log_audit(f"Sent {form.subject.data}: {form.body.data} to ({character.id}){character.name} with {form.attachment_count.data} of item {form.attachment.data}")
|
log_audit(f"Sent {form.subject.data}: \
|
||||||
|
{form.body.data} to ({character.id}){character.name} \
|
||||||
|
with {form.attachment_count.data} of item {form.attachment.data}")
|
||||||
else:
|
else:
|
||||||
Mail(
|
Mail(
|
||||||
sender_id = 0,
|
sender_id=0,
|
||||||
sender_name = f"[GM] {current_user.username}",
|
sender_name=f"[GM] {current_user.username}",
|
||||||
receiver_id = form.recipient.data,
|
receiver_id=form.recipient.data,
|
||||||
receiver_name = CharacterInfo.query.filter(CharacterInfo.id == form.recipient.data).first().name,
|
receiver_name=CharacterInfo.query.filter(CharacterInfo.id == form.recipient.data).first().name,
|
||||||
time_sent = time.time(),
|
time_sent=time.time(),
|
||||||
subject = form.subject.data,
|
subject=form.subject.data,
|
||||||
body = form.body.data,
|
body=form.body.data,
|
||||||
attachment_id = 0,
|
attachment_id=0,
|
||||||
attachment_lot = form.attachment.data,
|
attachment_lot=form.attachment.data,
|
||||||
attachment_count = form.attachment_count.data
|
attachment_count=form.attachment_count.data
|
||||||
).save()
|
).save()
|
||||||
log_audit(f"Sent {form.subject.data}: {form.body.data} to ({form.recipient.data}){CharacterInfo.query.filter(CharacterInfo.id == form.recipient.data).first().name} with {form.attachment_count.data} of item {form.attachment.data}")
|
log_audit(f"Sent {form.subject.data}: \
|
||||||
|
{form.body.data} to ({form.recipient.data}){CharacterInfo.query.filter(CharacterInfo.id == form.recipient.data).first().name} \
|
||||||
|
with {form.attachment_count.data} of item {form.attachment.data}")
|
||||||
|
|
||||||
flash("Sent Mail", "success")
|
flash("Sent Mail", "success")
|
||||||
return redirect(url_for('mail.send'))
|
return redirect(url_for('mail.send'))
|
||||||
|
|
||||||
|
|
||||||
recipients = CharacterInfo.query.all()
|
recipients = CharacterInfo.query.all()
|
||||||
for character in recipients:
|
for character in recipients:
|
||||||
form.recipient.choices.append((character.id, character.name))
|
form.recipient.choices.append((character.id, character.name))
|
||||||
@ -74,7 +76,7 @@ def send():
|
|||||||
for item in items:
|
for item in items:
|
||||||
name = translate_from_locale(f'Objects_{item[0]}_name')
|
name = translate_from_locale(f'Objects_{item[0]}_name')
|
||||||
if name == f'Objects_{item[0]}_name':
|
if name == f'Objects_{item[0]}_name':
|
||||||
name = (item[2] if (item[2] != "None" and item[2] !="" and item[2] != None) else item[1])
|
name = (item[2] if (item[2] != "None" and item[2] != "" and item[2] not None) else item[1])
|
||||||
form.attachment.choices.append(
|
form.attachment.choices.append(
|
||||||
(
|
(
|
||||||
item[0],
|
item[0],
|
||||||
|
11
app/main.py
11
app/main.py
@ -1,18 +1,15 @@
|
|||||||
from flask import render_template, Blueprint, redirect, request, send_from_directory, make_response, send_file, current_app
|
from flask import render_template, Blueprint, send_from_directory
|
||||||
from flask_user import login_required, current_user
|
from flask_user import current_user
|
||||||
import json, glob, os
|
|
||||||
from wand import image
|
|
||||||
|
|
||||||
from app.models import Account, AccountInvitation, CharacterInfo
|
from app.models import Account
|
||||||
from app.schemas import AccountSchema, CharacterInfoSchema
|
from app.schemas import AccountSchema, CharacterInfoSchema
|
||||||
from app.luclient import query_cdclient
|
|
||||||
from app import gm_level
|
|
||||||
|
|
||||||
main_blueprint = Blueprint('main', __name__)
|
main_blueprint = Blueprint('main', __name__)
|
||||||
|
|
||||||
account_schema = AccountSchema()
|
account_schema = AccountSchema()
|
||||||
char_info_schema = CharacterInfoSchema()
|
char_info_schema = CharacterInfoSchema()
|
||||||
|
|
||||||
|
|
||||||
@main_blueprint.route('/', methods=['GET'])
|
@main_blueprint.route('/', methods=['GET'])
|
||||||
def index():
|
def index():
|
||||||
"""Home/Index Page"""
|
"""Home/Index Page"""
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
from flask_migrate import Migrate
|
from flask_migrate import Migrate
|
||||||
from flask_user import UserMixin, current_user
|
from flask_user import UserMixin
|
||||||
from wtforms import ValidationError
|
from wtforms import ValidationError
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -12,6 +12,7 @@ from time import sleep
|
|||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
|
||||||
|
|
||||||
# retrying query to work around python trash collector
|
# retrying query to work around python trash collector
|
||||||
# killing connections of other gunicorn workers
|
# killing connections of other gunicorn workers
|
||||||
class RetryingQuery(BaseQuery):
|
class RetryingQuery(BaseQuery):
|
||||||
@ -46,9 +47,11 @@ class RetryingQuery(BaseQuery):
|
|||||||
raise
|
raise
|
||||||
self.session.rollback()
|
self.session.rollback()
|
||||||
|
|
||||||
|
|
||||||
db = SQLAlchemy(query_class=RetryingQuery)
|
db = SQLAlchemy(query_class=RetryingQuery)
|
||||||
migrate = Migrate()
|
migrate = Migrate()
|
||||||
|
|
||||||
|
|
||||||
class PlayKey(db.Model):
|
class PlayKey(db.Model):
|
||||||
__tablename__ = 'play_keys'
|
__tablename__ = 'play_keys'
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
@ -121,6 +124,7 @@ class PlayKey(db.Model):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
db.session.refresh(self)
|
db.session.refresh(self)
|
||||||
|
|
||||||
|
|
||||||
class Account(db.Model, UserMixin):
|
class Account(db.Model, UserMixin):
|
||||||
__tablename__ = 'accounts'
|
__tablename__ = 'accounts'
|
||||||
id = db.Column(
|
id = db.Column(
|
||||||
@ -200,7 +204,7 @@ class Account(db.Model, UserMixin):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_user_by_id(*, user_id=None):
|
def get_user_by_id(*, user_id=None):
|
||||||
return User.query.filter(user_id == User.id).first()
|
return Account.query.filter(user_id == Account.id).first()
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
db.session.add(self)
|
db.session.add(self)
|
||||||
@ -211,6 +215,7 @@ class Account(db.Model, UserMixin):
|
|||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class AccountInvitation(db.Model):
|
class AccountInvitation(db.Model):
|
||||||
__tablename__ = 'account_invites'
|
__tablename__ = 'account_invites'
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
@ -245,14 +250,10 @@ class AccountInvitation(db.Model):
|
|||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_user_by_id(*, user_id=None):
|
def get_user_by_id(*, user_id=None):
|
||||||
return User.query.filter(user_id == User.id).first()
|
return Account.query.filter(user_id == Account.id).first()
|
||||||
|
|
||||||
def delete(self):
|
|
||||||
db.session.delete(self)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
# This table is cursed, see prop_clone_id
|
# This table is cursed, see prop_clone_id
|
||||||
class CharacterInfo(db.Model):
|
class CharacterInfo(db.Model):
|
||||||
@ -327,6 +328,7 @@ class CharacterInfo(db.Model):
|
|||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class CharacterXML(db.Model):
|
class CharacterXML(db.Model):
|
||||||
__tablename__ = 'charxml'
|
__tablename__ = 'charxml'
|
||||||
id = db.Column(
|
id = db.Column(
|
||||||
@ -348,6 +350,7 @@ class CharacterXML(db.Model):
|
|||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class CommandLog(db.Model):
|
class CommandLog(db.Model):
|
||||||
__tablename__ = 'command_log'
|
__tablename__ = 'command_log'
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
@ -364,7 +367,7 @@ class CommandLog(db.Model):
|
|||||||
passive_deletes=True
|
passive_deletes=True
|
||||||
)
|
)
|
||||||
|
|
||||||
command = db.Column(
|
command = db.Column(
|
||||||
mysql.VARCHAR(256),
|
mysql.VARCHAR(256),
|
||||||
nullable=False
|
nullable=False
|
||||||
)
|
)
|
||||||
@ -378,6 +381,7 @@ class CommandLog(db.Model):
|
|||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class Friends(db.Model):
|
class Friends(db.Model):
|
||||||
__tablename__ = 'friends'
|
__tablename__ = 'friends'
|
||||||
player_id = db.Column(
|
player_id = db.Column(
|
||||||
@ -423,6 +427,7 @@ class Friends(db.Model):
|
|||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class Leaderboard(db.Model):
|
class Leaderboard(db.Model):
|
||||||
__tablename__ = 'leaderboard'
|
__tablename__ = 'leaderboard'
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
@ -472,6 +477,7 @@ class Leaderboard(db.Model):
|
|||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class Mail(db.Model):
|
class Mail(db.Model):
|
||||||
__tablename__ = 'mail'
|
__tablename__ = 'mail'
|
||||||
id = db.Column(
|
id = db.Column(
|
||||||
@ -560,6 +566,7 @@ class Mail(db.Model):
|
|||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class ObjectIDTracker(db.Model):
|
class ObjectIDTracker(db.Model):
|
||||||
__tablename__ = 'object_id_tracker'
|
__tablename__ = 'object_id_tracker'
|
||||||
last_object_id = db.Column(
|
last_object_id = db.Column(
|
||||||
@ -569,6 +576,7 @@ class ObjectIDTracker(db.Model):
|
|||||||
server_default='0'
|
server_default='0'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PetNames(db.Model):
|
class PetNames(db.Model):
|
||||||
__tablename__ = 'pet_names'
|
__tablename__ = 'pet_names'
|
||||||
id = db.Column(mysql.BIGINT, primary_key=True)
|
id = db.Column(mysql.BIGINT, primary_key=True)
|
||||||
@ -582,7 +590,7 @@ class PetNames(db.Model):
|
|||||||
server_default='0'
|
server_default='0'
|
||||||
)
|
)
|
||||||
|
|
||||||
owner_id = db.Column(
|
owner_id = db.Column(
|
||||||
mysql.BIGINT,
|
mysql.BIGINT,
|
||||||
nullable=True
|
nullable=True
|
||||||
)
|
)
|
||||||
@ -605,7 +613,7 @@ class Property(db.Model):
|
|||||||
autoincrement=False
|
autoincrement=False
|
||||||
)
|
)
|
||||||
|
|
||||||
owner_id = db.Column(
|
owner_id = db.Column(
|
||||||
mysql.BIGINT,
|
mysql.BIGINT,
|
||||||
db.ForeignKey(CharacterInfo.id, ondelete='CASCADE'),
|
db.ForeignKey(CharacterInfo.id, ondelete='CASCADE'),
|
||||||
nullable=False
|
nullable=False
|
||||||
@ -623,7 +631,7 @@ class Property(db.Model):
|
|||||||
nullable=False,
|
nullable=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
clone_id = db.Column(
|
clone_id = db.Column(
|
||||||
mysql.BIGINT(unsigned=True),
|
mysql.BIGINT(unsigned=True),
|
||||||
db.ForeignKey(CharacterInfo.prop_clone_id, ondelete='CASCADE'),
|
db.ForeignKey(CharacterInfo.prop_clone_id, ondelete='CASCADE'),
|
||||||
)
|
)
|
||||||
@ -763,6 +771,7 @@ class UGC(db.Model):
|
|||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class PropertyContent(db.Model):
|
class PropertyContent(db.Model):
|
||||||
__tablename__ = 'properties_contents'
|
__tablename__ = 'properties_contents'
|
||||||
id = db.Column(
|
id = db.Column(
|
||||||
@ -843,6 +852,7 @@ class PropertyContent(db.Model):
|
|||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class ActivityLog(db.Model):
|
class ActivityLog(db.Model):
|
||||||
__tablename__ = 'activity_log'
|
__tablename__ = 'activity_log'
|
||||||
id = db.Column(mysql.INTEGER, primary_key=True)
|
id = db.Column(mysql.INTEGER, primary_key=True)
|
||||||
@ -883,6 +893,7 @@ class ActivityLog(db.Model):
|
|||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class BugReport(db.Model):
|
class BugReport(db.Model):
|
||||||
__tablename__ = 'bug_reports'
|
__tablename__ = 'bug_reports'
|
||||||
id = db.Column(mysql.INTEGER, primary_key=True)
|
id = db.Column(mysql.INTEGER, primary_key=True)
|
||||||
@ -944,6 +955,7 @@ class BugReport(db.Model):
|
|||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class Server(db.Model):
|
class Server(db.Model):
|
||||||
__tablename__ = 'servers'
|
__tablename__ = 'servers'
|
||||||
id = db.Column(
|
id = db.Column(
|
||||||
@ -1016,6 +1028,7 @@ class Reports(db.Model):
|
|||||||
db.session.delete(self)
|
db.session.delete(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class AuditLog(db.Model):
|
class AuditLog(db.Model):
|
||||||
__tablename__ = 'audit_logs'
|
__tablename__ = 'audit_logs'
|
||||||
id = db.Column(
|
id = db.Column(
|
||||||
|
@ -2,7 +2,6 @@ from flask import render_template, Blueprint, redirect, url_for, request, flash,
|
|||||||
from flask_user import login_required
|
from flask_user import login_required
|
||||||
from app.models import PetNames, db, CharacterXML, CharacterInfo
|
from app.models import PetNames, db, CharacterXML, CharacterInfo
|
||||||
from datatables import ColumnDT, DataTables
|
from datatables import ColumnDT, DataTables
|
||||||
from app.forms import CreatePlayKeyForm, EditPlayKeyForm
|
|
||||||
from app import gm_level, log_audit, scheduler
|
from app import gm_level, log_audit, scheduler
|
||||||
|
|
||||||
moderation_blueprint = Blueprint('moderation', __name__)
|
moderation_blueprint = Blueprint('moderation', __name__)
|
||||||
@ -20,7 +19,7 @@ def index(status):
|
|||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
def approve_pet(id):
|
def approve_pet(id):
|
||||||
|
|
||||||
pet_data = PetNames.query.filter(PetNames.id == id).first()
|
pet_data = PetNames.query.filter(PetNames.id == id).first()
|
||||||
|
|
||||||
pet_data.approved = 2
|
pet_data.approved = 2
|
||||||
log_audit(f"Approved pet name {pet_data.pet_name} from {pet_data.owner_id}")
|
log_audit(f"Approved pet name {pet_data.pet_name} from {pet_data.owner_id}")
|
||||||
@ -34,7 +33,7 @@ def approve_pet(id):
|
|||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
def reject_pet(id):
|
def reject_pet(id):
|
||||||
|
|
||||||
pet_data = PetNames.query.filter(PetNames.id == id).first()
|
pet_data = PetNames.query.filter(PetNames.id == id).first()
|
||||||
|
|
||||||
pet_data.approved = 0
|
pet_data.approved = 0
|
||||||
log_audit(f"Rejected pet name {pet_data.pet_name} from {pet_data.owner_id}")
|
log_audit(f"Rejected pet name {pet_data.pet_name} from {pet_data.owner_id}")
|
||||||
@ -55,16 +54,15 @@ def get_pets(status="all"):
|
|||||||
]
|
]
|
||||||
|
|
||||||
query = None
|
query = None
|
||||||
if status=="all":
|
if status == "all":
|
||||||
query = db.session.query().select_from(PetNames)
|
query = db.session.query().select_from(PetNames)
|
||||||
elif status=="approved":
|
elif status == "approved":
|
||||||
query = db.session.query().select_from(PetNames).filter(PetNames.approved==2)
|
query = db.session.query().select_from(PetNames).filter(PetNames.approved == 2)
|
||||||
elif status=="unapproved":
|
elif status == "unapproved":
|
||||||
query = db.session.query().select_from(PetNames).filter(PetNames.approved==1)
|
query = db.session.query().select_from(PetNames).filter(PetNames.approved == 1)
|
||||||
else:
|
else:
|
||||||
raise Exception("Not a valid filter")
|
raise Exception("Not a valid filter")
|
||||||
|
|
||||||
|
|
||||||
params = request.args.to_dict()
|
params = request.args.to_dict()
|
||||||
|
|
||||||
rowTable = DataTables(params, query, columns)
|
rowTable = DataTables(params, query, columns)
|
||||||
@ -116,8 +114,8 @@ def get_pets(status="all"):
|
|||||||
{CharacterInfo.query.filter(CharacterInfo.id==pet_data['3']).first().name}
|
{CharacterInfo.query.filter(CharacterInfo.id==pet_data['3']).first().name}
|
||||||
</a>
|
</a>
|
||||||
"""
|
"""
|
||||||
except Exception as e:
|
except Exception:
|
||||||
PetNames.query.filter(PetNames.id==id).first().delete()
|
PetNames.query.filter(PetNames.id == id).first().delete()
|
||||||
pet_data["0"] = "<span class='text-danger'>Deleted Refresh to make go away</span>"
|
pet_data["0"] = "<span class='text-danger'>Deleted Refresh to make go away</span>"
|
||||||
pet_data["3"] = "<span class='text-danger'>Character Deleted</span>"
|
pet_data["3"] = "<span class='text-danger'>Character Deleted</span>"
|
||||||
else:
|
else:
|
||||||
@ -131,7 +129,7 @@ def pet_name_maintenance():
|
|||||||
with scheduler.app.app_context():
|
with scheduler.app.app_context():
|
||||||
# associate pet names to characters
|
# associate pet names to characters
|
||||||
current_app.logger.info("Started Pet Name Maintenance")
|
current_app.logger.info("Started Pet Name Maintenance")
|
||||||
unassociated_pets = PetNames.query.filter(PetNames.owner_id == None).all()
|
unassociated_pets = PetNames.query.filter(PetNames.owner_id is None).all()
|
||||||
if unassociated_pets:
|
if unassociated_pets:
|
||||||
current_app.logger.info("Found un-associated pets")
|
current_app.logger.info("Found un-associated pets")
|
||||||
for pet in unassociated_pets:
|
for pet in unassociated_pets:
|
||||||
@ -143,11 +141,11 @@ def pet_name_maintenance():
|
|||||||
pet.delete()
|
pet.delete()
|
||||||
|
|
||||||
# auto-moderate based on already moderated names
|
# auto-moderate based on already moderated names
|
||||||
unmoderated_pets = PetNames.query.filter(PetNames.approved==1).all()
|
unmoderated_pets = PetNames.query.filter(PetNames.approved == 1).all()
|
||||||
if unmoderated_pets:
|
if unmoderated_pets:
|
||||||
current_app.logger.info("Found un-moderated Pets")
|
current_app.logger.info("Found un-moderated Pets")
|
||||||
for pet in unmoderated_pets:
|
for pet in unmoderated_pets:
|
||||||
existing_pet = PetNames.query.filter(PetNames.approved.in_([0,2])).filter(PetNames.pet_name == pet.pet_name).first()
|
existing_pet = PetNames.query.filter(PetNames.approved.in_([0, 2])).filter(PetNames.pet_name == pet.pet_name).first()
|
||||||
if existing_pet:
|
if existing_pet:
|
||||||
pet.approved = existing_pet.approved
|
pet.approved = existing_pet.approved
|
||||||
pet.save()
|
pet.save()
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
from flask import render_template, Blueprint, redirect, url_for, request, abort, flash
|
from flask import render_template, Blueprint, redirect, url_for, request, flash
|
||||||
from flask_user import login_required, current_user
|
from flask_user import login_required
|
||||||
from app.models import Account, AccountInvitation, PlayKey, db
|
from app.models import Account, PlayKey, db
|
||||||
from datatables import ColumnDT, DataTables
|
from datatables import ColumnDT, DataTables
|
||||||
from app.forms import CreatePlayKeyForm, EditPlayKeyForm
|
from app.forms import CreatePlayKeyForm, EditPlayKeyForm
|
||||||
from app import gm_level, log_audit
|
from app import gm_level, log_audit
|
||||||
|
|
||||||
play_keys_blueprint = Blueprint('play_keys', __name__)
|
play_keys_blueprint = Blueprint('play_keys', __name__)
|
||||||
|
|
||||||
# Key creation page
|
|
||||||
|
|
||||||
|
# Key creation page
|
||||||
@play_keys_blueprint.route('/', methods=['GET'])
|
@play_keys_blueprint.route('/', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@gm_level(9)
|
@gm_level(9)
|
||||||
@ -45,7 +45,7 @@ def bulk_create():
|
|||||||
@gm_level(9)
|
@gm_level(9)
|
||||||
def delete(id):
|
def delete(id):
|
||||||
key = PlayKey.query.filter(PlayKey.id == id).first()
|
key = PlayKey.query.filter(PlayKey.id == id).first()
|
||||||
associated_accounts = Account.query.filter(Account.play_key_id==id).all()
|
# associated_accounts = Account.query.filter(Account.play_key_id==id).all()
|
||||||
log_audit(f"Deleted Play Key {key.key_string}")
|
log_audit(f"Deleted Play Key {key.key_string}")
|
||||||
flash(f"Deleted Play Key {key.key_string}", "danger")
|
flash(f"Deleted Play Key {key.key_string}", "danger")
|
||||||
key.delete()
|
key.delete()
|
||||||
@ -56,7 +56,7 @@ def delete(id):
|
|||||||
@login_required
|
@login_required
|
||||||
@gm_level(9)
|
@gm_level(9)
|
||||||
def edit(id):
|
def edit(id):
|
||||||
key = PlayKey.query.filter(PlayKey.id==id).first()
|
key = PlayKey.query.filter(PlayKey.id == id).first()
|
||||||
form = EditPlayKeyForm()
|
form = EditPlayKeyForm()
|
||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
@ -84,7 +84,7 @@ def edit(id):
|
|||||||
@gm_level(9)
|
@gm_level(9)
|
||||||
def view(id):
|
def view(id):
|
||||||
key = PlayKey.query.filter(PlayKey.id == id).first()
|
key = PlayKey.query.filter(PlayKey.id == id).first()
|
||||||
accounts = Account.query.filter(Account.play_key_id==id).all()
|
accounts = Account.query.filter(Account.play_key_id == id).all()
|
||||||
return render_template('play_keys/view.html.j2', key=key, accounts=accounts)
|
return render_template('play_keys/view.html.j2', key=key, accounts=accounts)
|
||||||
|
|
||||||
|
|
||||||
@ -125,7 +125,12 @@ def get():
|
|||||||
Delete
|
Delete
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="modal fade bd-example-modal-lg" id="delete-{play_key["1"]}-modal" tabindex="-1" role="dialog" aria-labelledby="delete-{play_key["1"]}-modalLabel" aria-hidden="true">
|
<div class="modal
|
||||||
|
fade bd-example-modal-lg"
|
||||||
|
id="delete-{play_key["1"]}-modal"
|
||||||
|
tabindex="-1" role="dialog"
|
||||||
|
aria-labelledby="delete-{play_key["1"]}-modalLabel"
|
||||||
|
aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<div class="modal-content bg-dark border-primary">
|
<div class="modal-content bg-dark border-primary">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
|
@ -5,14 +5,11 @@ from flask import (
|
|||||||
url_for,
|
url_for,
|
||||||
request,
|
request,
|
||||||
abort,
|
abort,
|
||||||
jsonify,
|
|
||||||
send_from_directory,
|
|
||||||
make_response,
|
make_response,
|
||||||
flash,
|
flash,
|
||||||
current_app
|
current_app
|
||||||
)
|
)
|
||||||
from flask_user import login_required, current_user
|
from flask_user import login_required, current_user
|
||||||
import json
|
|
||||||
from datatables import ColumnDT, DataTables
|
from datatables import ColumnDT, DataTables
|
||||||
import time
|
import time
|
||||||
from app.models import Property, db, UGC, CharacterInfo, PropertyContent, Account
|
from app.models import Property, db, UGC, CharacterInfo, PropertyContent, Account
|
||||||
@ -21,8 +18,6 @@ from app import gm_level, log_audit
|
|||||||
from app.luclient import query_cdclient
|
from app.luclient import query_cdclient
|
||||||
|
|
||||||
import zlib
|
import zlib
|
||||||
import xmltodict
|
|
||||||
import os
|
|
||||||
import app.pylddlib as ldd
|
import app.pylddlib as ldd
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
@ -30,6 +25,7 @@ property_blueprint = Blueprint('properties', __name__)
|
|||||||
|
|
||||||
property_schema = PropertySchema()
|
property_schema = PropertySchema()
|
||||||
|
|
||||||
|
|
||||||
@property_blueprint.route('/', methods=['GET'])
|
@property_blueprint.route('/', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
@ -42,7 +38,7 @@ def index():
|
|||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
def approve(id):
|
def approve(id):
|
||||||
|
|
||||||
property_data = Property.query.filter(Property.id == id).first()
|
property_data = Property.query.filter(Property.id == id).first()
|
||||||
|
|
||||||
property_data.mod_approved = not property_data.mod_approved
|
property_data.mod_approved = not property_data.mod_approved
|
||||||
|
|
||||||
@ -89,8 +85,6 @@ def approve(id):
|
|||||||
else:
|
else:
|
||||||
go_to = url_for('main.index')
|
go_to = url_for('main.index')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return redirect(go_to)
|
return redirect(go_to)
|
||||||
|
|
||||||
|
|
||||||
@ -134,16 +128,19 @@ def get(status="all"):
|
|||||||
]
|
]
|
||||||
|
|
||||||
query = None
|
query = None
|
||||||
if status=="all":
|
if status == "all":
|
||||||
query = db.session.query().select_from(Property).join(CharacterInfo, CharacterInfo.id==Property.owner_id).join(Account)
|
query = db.session.query().select_from(Property).join(CharacterInfo, CharacterInfo.id == Property.owner_id).join(Account)
|
||||||
elif status=="approved":
|
elif status == "approved":
|
||||||
query = db.session.query().select_from(Property).join(CharacterInfo, CharacterInfo.id==Property.owner_id).join(Account).filter(Property.mod_approved==True).filter(Property.privacy_option==2)
|
query = db.session.query().select_from(Property).join(
|
||||||
elif status=="unapproved":
|
CharacterInfo, CharacterInfo.id == Property.owner_id
|
||||||
query = db.session.query().select_from(Property).join(CharacterInfo, CharacterInfo.id==Property.owner_id).join(Account).filter(Property.mod_approved==False).filter(Property.privacy_option==2)
|
).join(Account).filter(Property.mod_approved is True).filter(Property.privacy_option == 2)
|
||||||
|
elif status == "unapproved":
|
||||||
|
query = db.session.query().select_from(Property).join(
|
||||||
|
CharacterInfo, CharacterInfo.id == Property.owner_id
|
||||||
|
).join(Account).filter(Property.mod_approved is False).filter(Property.privacy_option == 2)
|
||||||
else:
|
else:
|
||||||
raise Exception("Not a valid filter")
|
raise Exception("Not a valid filter")
|
||||||
|
|
||||||
|
|
||||||
params = request.args.to_dict()
|
params = request.args.to_dict()
|
||||||
|
|
||||||
rowTable = DataTables(params, query, columns)
|
rowTable = DataTables(params, query, columns)
|
||||||
@ -183,10 +180,10 @@ def get(status="all"):
|
|||||||
|
|
||||||
if property_data["4"] == "":
|
if property_data["4"] == "":
|
||||||
property_data["4"] = query_cdclient(
|
property_data["4"] = query_cdclient(
|
||||||
'select DisplayDescription from ZoneTable where zoneID = ?',
|
'select DisplayDescription from ZoneTable where zoneID = ?',
|
||||||
[property_data["12"]],
|
[property_data["12"]],
|
||||||
one=True
|
one=True
|
||||||
)
|
)
|
||||||
|
|
||||||
if property_data["6"] == 0:
|
if property_data["6"] == 0:
|
||||||
property_data["6"] = "Private"
|
property_data["6"] = "Private"
|
||||||
@ -215,7 +212,7 @@ def get(status="all"):
|
|||||||
@property_blueprint.route('/view_model/<id>/<lod>', methods=['GET'])
|
@property_blueprint.route('/view_model/<id>/<lod>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def view_model(id, lod):
|
def view_model(id, lod):
|
||||||
property_content_data = PropertyContent.query.filter(PropertyContent.id==id).all()
|
property_content_data = PropertyContent.query.filter(PropertyContent.id == id).all()
|
||||||
|
|
||||||
# TODO: Restrict somehow
|
# TODO: Restrict somehow
|
||||||
formatted_data = [
|
formatted_data = [
|
||||||
@ -242,6 +239,7 @@ def view_model(id, lod):
|
|||||||
lod=lod
|
lod=lod
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
property_center = {
|
property_center = {
|
||||||
1150: "(-17, 432, -60)",
|
1150: "(-17, 432, -60)",
|
||||||
1151: "(0, 455, -110)",
|
1151: "(0, 455, -110)",
|
||||||
@ -256,7 +254,7 @@ property_center = {
|
|||||||
@login_required
|
@login_required
|
||||||
def view_models(id, lod):
|
def view_models(id, lod):
|
||||||
property_content_data = PropertyContent.query.filter(
|
property_content_data = PropertyContent.query.filter(
|
||||||
PropertyContent.property_id==id
|
PropertyContent.property_id == id
|
||||||
).order_by(PropertyContent.lot).all()
|
).order_by(PropertyContent.lot).all()
|
||||||
|
|
||||||
consolidated_list = []
|
consolidated_list = []
|
||||||
@ -295,7 +293,7 @@ def view_models(id, lod):
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
property_data = Property.query.filter(Property.id==id).first()
|
property_data = Property.query.filter(Property.id == id).first()
|
||||||
return render_template(
|
return render_template(
|
||||||
'ldd/ldd.html.j2',
|
'ldd/ldd.html.j2',
|
||||||
property_data=property_data,
|
property_data=property_data,
|
||||||
@ -304,30 +302,30 @@ def view_models(id, lod):
|
|||||||
lod=lod
|
lod=lod
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@property_blueprint.route('/get_model/<id>/<file_format>/<lod>', methods=['GET'])
|
@property_blueprint.route('/get_model/<id>/<file_format>/<lod>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def get_model(id, file_format, lod):
|
def get_model(id, file_format, lod):
|
||||||
content = PropertyContent.query.filter(PropertyContent.id==id).first()
|
content = PropertyContent.query.filter(PropertyContent.id == id).first()
|
||||||
if not(0 <= int(lod) <= 2):
|
if not(0 <= int(lod) <= 2):
|
||||||
abort(404)
|
abort(404)
|
||||||
if content.lot == 14: # ugc model
|
if content.lot == 14: # ugc model
|
||||||
response = ugc(content)[0]
|
response = ugc(content)[0]
|
||||||
else: # prebuild model
|
else: # prebuilt model
|
||||||
response = prebuilt(content, file_format, lod)[0]
|
response = prebuilt(content, file_format, lod)[0]
|
||||||
|
|
||||||
response.headers.set('Content-Type', 'text/xml')
|
response.headers.set('Content-Type', 'text/xml')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@property_blueprint.route('/download_model/<id>', methods=['GET'])
|
@property_blueprint.route('/download_model/<id>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def download_model(id):
|
def download_model(id):
|
||||||
content = PropertyContent.query.filter(PropertyContent.id==id).first()
|
content = PropertyContent.query.filter(PropertyContent.id == id).first()
|
||||||
|
|
||||||
if content.lot == 14: # ugc model
|
if content.lot == 14: # ugc model
|
||||||
response, filename = ugc(content)
|
response, filename = ugc(content)
|
||||||
else: # prebuild model
|
else: # prebuilt model
|
||||||
response, filename = prebuilt(content, "lxfml")
|
response, filename = prebuilt(content, "lxfml")
|
||||||
|
|
||||||
response.headers.set('Content-Type', 'attachment/xml')
|
response.headers.set('Content-Type', 'attachment/xml')
|
||||||
@ -340,7 +338,7 @@ def download_model(id):
|
|||||||
|
|
||||||
|
|
||||||
def ugc(content):
|
def ugc(content):
|
||||||
ugc_data = UGC.query.filter(UGC.id==content.ugc_id).first()
|
ugc_data = UGC.query.filter(UGC.id == content.ugc_id).first()
|
||||||
uncompressed_lxfml = zlib.decompress(ugc_data.lxfml)
|
uncompressed_lxfml = zlib.decompress(ugc_data.lxfml)
|
||||||
response = make_response(uncompressed_lxfml)
|
response = make_response(uncompressed_lxfml)
|
||||||
return response, ugc_data.filename
|
return response, ugc_data.filename
|
||||||
@ -355,7 +353,8 @@ def prebuilt(content, file_format, lod):
|
|||||||
one=True
|
one=True
|
||||||
)[0]
|
)[0]
|
||||||
# find the asset from rendercomponent given the component id
|
# find the asset from rendercomponent given the component id
|
||||||
filename = query_cdclient('select render_asset from RenderComponent where id = ?',
|
filename = query_cdclient(
|
||||||
|
'select render_asset from RenderComponent where id = ?',
|
||||||
[render_component_id],
|
[render_component_id],
|
||||||
one=True
|
one=True
|
||||||
)
|
)
|
||||||
@ -375,7 +374,7 @@ def prebuilt(content, file_format, lod):
|
|||||||
cache = pathlib.Path(f'app/cache/BrickModels/{filename}.lod{lod}.{file_format}')
|
cache = pathlib.Path(f'app/cache/BrickModels/{filename}.lod{lod}.{file_format}')
|
||||||
cache.parent.mkdir(parents=True, exist_ok=True)
|
cache.parent.mkdir(parents=True, exist_ok=True)
|
||||||
try:
|
try:
|
||||||
ldd.main(str(lxfml.as_posix()), str(cache.with_suffix("").as_posix()), lod) # convert to OBJ
|
ldd.main(str(lxfml.as_posix()), str(cache.with_suffix("").as_posix()), lod) # convert to OBJ
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
current_app.logger.error(f"ERROR on {cache}:\n {e}")
|
current_app.logger.error(f"ERROR on {cache}:\n {e}")
|
||||||
|
|
||||||
|
361
app/pylddlib.py
361
app/pylddlib.py
@ -1,33 +1,12 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# pylddlib version 0.4.9.7
|
# pylddlib version 0.4.9.7
|
||||||
# based on pyldd2obj version 0.4.8 - Copyright (c) 2019 by jonnysp
|
# based on pyldd2obj version 0.4.8 - Copyright (c) 2019 by jonnysp
|
||||||
#
|
|
||||||
# Updates:
|
|
||||||
# 0.4.9.8 Make work with LEGO Universe brickdb
|
|
||||||
# 0.4.9.7 corrected bug of incorrectly parsing the primitive xml file, specifically with comments. Add support LDDLIFTREE envirnment variable to set location of db.lif.
|
|
||||||
# 0.4.9.6 preliminary Linux support
|
|
||||||
# 0.4.9.5 corrected bug of incorrectly Bounding / GeometryBounding parsing the primitive xml file.
|
|
||||||
# 0.4.9.4 improved lif.db checking for crucial files (because of the infamous botched 4.3.12 LDD Windows update).
|
|
||||||
# 0.4.9.3 improved Windows and Python 3 compatibility
|
|
||||||
# 0.4.9.2 changed handling of material = 0 for a part. Now a 0 will choose the 1st material (the base material of a part) and not the previous material of the subpart before. This will fix "Chicken Helmet Part 11262". It may break other parts and this change needs further regression.
|
|
||||||
# 0.4.9.1 improved custom2DField handling, fixed decorations bug, improved material assignments handling
|
|
||||||
# 0.4.9 updates to support reading extracted db.lif from db folder
|
|
||||||
#
|
|
||||||
# License: MIT License
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import platform
|
|
||||||
import sys
|
import sys
|
||||||
import math
|
import math
|
||||||
import struct
|
import struct
|
||||||
import zipfile
|
import zipfile
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
import time
|
|
||||||
|
|
||||||
if sys.version_info < (3, 0):
|
|
||||||
reload(sys)
|
|
||||||
sys.setdefaultencoding('utf-8')
|
|
||||||
|
|
||||||
PRIMITIVEPATH = '/Primitives/'
|
PRIMITIVEPATH = '/Primitives/'
|
||||||
GEOMETRIEPATH = PRIMITIVEPATH
|
GEOMETRIEPATH = PRIMITIVEPATH
|
||||||
@ -36,8 +15,9 @@ MATERIALNAMESPATH = '/MaterialNames/'
|
|||||||
|
|
||||||
LOGOONSTUDSCONNTYPE = {"0:4", "0:4:1", "0:4:2", "0:4:33", "2:4:1", "2:4:34"}
|
LOGOONSTUDSCONNTYPE = {"0:4", "0:4:1", "0:4:2", "0:4:33", "2:4:1", "2:4:34"}
|
||||||
|
|
||||||
|
|
||||||
class Matrix3D:
|
class Matrix3D:
|
||||||
def __init__(self, n11=1,n12=0,n13=0,n14=0,n21=0,n22=1,n23=0,n24=0,n31=0,n32=0,n33=1,n34=0,n41=0,n42=0,n43=0,n44=1):
|
def __init__(self, n11=1, n12=0, n13=0, n14=0, n21=0, n22=1, n23=0, n24=0, n31=0, n32=0, n33=1, n34=0, n41=0, n42=0, n43=0, n44=1):
|
||||||
self.n11 = n11
|
self.n11 = n11
|
||||||
self.n12 = n12
|
self.n12 = n12
|
||||||
self.n13 = n13
|
self.n13 = n13
|
||||||
@ -56,9 +36,26 @@ class Matrix3D:
|
|||||||
self.n44 = n44
|
self.n44 = n44
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '[{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}]'.format(self.n11, self.n12, self.n13,self.n14,self.n21, self.n22, self.n23,self.n24,self.n31, self.n32, self.n33,self.n34,self.n41, self.n42, self.n43,self.n44)
|
return '[{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15}]'.format(
|
||||||
|
self.n11,
|
||||||
|
self.n12,
|
||||||
|
self.n13,
|
||||||
|
self.n14,
|
||||||
|
self.n21,
|
||||||
|
self.n22,
|
||||||
|
self.n23,
|
||||||
|
self.n24,
|
||||||
|
self.n31,
|
||||||
|
self.n32,
|
||||||
|
self.n33,
|
||||||
|
self.n34,
|
||||||
|
self.n41,
|
||||||
|
self.n42,
|
||||||
|
self.n43,
|
||||||
|
self.n44
|
||||||
|
)
|
||||||
|
|
||||||
def rotate(self,angle=0,axis=0):
|
def rotate(self, angle=0, axis=0):
|
||||||
c = math.cos(angle)
|
c = math.cos(angle)
|
||||||
s = math.sin(angle)
|
s = math.sin(angle)
|
||||||
t = 1 - c
|
t = 1 - c
|
||||||
@ -109,21 +106,22 @@ class Matrix3D:
|
|||||||
self.n12 * other.n41 + self.n22 * other.n42 + self.n32 * other.n43 + self.n42 * other.n44,
|
self.n12 * other.n41 + self.n22 * other.n42 + self.n32 * other.n43 + self.n42 * other.n44,
|
||||||
self.n13 * other.n41 + self.n23 * other.n42 + self.n33 * other.n43 + self.n43 * other.n44,
|
self.n13 * other.n41 + self.n23 * other.n42 + self.n33 * other.n43 + self.n43 * other.n44,
|
||||||
self.n14 * other.n41 + self.n24 * other.n42 + self.n34 * other.n43 + self.n44 * other.n44
|
self.n14 * other.n41 + self.n24 * other.n42 + self.n34 * other.n43 + self.n44 * other.n44
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Point3D:
|
class Point3D:
|
||||||
def __init__(self, x=0,y=0,z=0):
|
def __init__(self, x=0, y=0, z=0):
|
||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
self.z = z
|
self.z = z
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '[{0},{1},{2}]'.format(self.x, self.y,self.z)
|
return '[{0},{1},{2}]'.format(self.x, self.y, self.z)
|
||||||
|
|
||||||
def string(self,prefix = "v"):
|
def string(self, prefix="v"):
|
||||||
return '{0} {1:f} {2:f} {3:f}\n'.format(prefix ,self.x , self.y, self.z)
|
return '{0} {1:f} {2:f} {3:f}\n'.format(prefix, self.x, self.y, self.z)
|
||||||
|
|
||||||
def transformW(self,matrix):
|
def transformW(self, matrix):
|
||||||
x = matrix.n11 * self.x + matrix.n21 * self.y + matrix.n31 * self.z
|
x = matrix.n11 * self.x + matrix.n21 * self.y + matrix.n31 * self.z
|
||||||
y = matrix.n12 * self.x + matrix.n22 * self.y + matrix.n32 * self.z
|
y = matrix.n12 * self.x + matrix.n22 * self.y + matrix.n32 * self.z
|
||||||
z = matrix.n13 * self.x + matrix.n23 * self.y + matrix.n33 * self.z
|
z = matrix.n13 * self.x + matrix.n23 * self.y + matrix.n33 * self.z
|
||||||
@ -131,7 +129,7 @@ class Point3D:
|
|||||||
self.y = y
|
self.y = y
|
||||||
self.z = z
|
self.z = z
|
||||||
|
|
||||||
def transform(self,matrix):
|
def transform(self, matrix):
|
||||||
x = matrix.n11 * self.x + matrix.n21 * self.y + matrix.n31 * self.z + matrix.n41
|
x = matrix.n11 * self.x + matrix.n21 * self.y + matrix.n31 * self.z + matrix.n41
|
||||||
y = matrix.n12 * self.x + matrix.n22 * self.y + matrix.n32 * self.z + matrix.n42
|
y = matrix.n12 * self.x + matrix.n22 * self.y + matrix.n32 * self.z + matrix.n42
|
||||||
z = matrix.n13 * self.x + matrix.n23 * self.y + matrix.n33 * self.z + matrix.n43
|
z = matrix.n13 * self.x + matrix.n23 * self.y + matrix.n33 * self.z + matrix.n43
|
||||||
@ -140,41 +138,58 @@ class Point3D:
|
|||||||
self.z = z
|
self.z = z
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
return Point3D(x=self.x,y=self.y,z=self.z)
|
return Point3D(x=self.x, y=self.y, z=self.z)
|
||||||
|
|
||||||
|
|
||||||
class Point2D:
|
class Point2D:
|
||||||
def __init__(self, x=0,y=0):
|
def __init__(self, x=0, y=0):
|
||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '[{0},{1}]'.format(self.x, self.y * -1)
|
return '[{0},{1}]'.format(self.x, self.y * -1)
|
||||||
def string(self,prefix="t"):
|
|
||||||
return '{0} {1:f} {2:f}\n'.format(prefix , self.x, self.y * -1 )
|
def string(self, prefix="t"):
|
||||||
|
return '{0} {1:f} {2:f}\n'.format(prefix, self.x, self.y * -1)
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
return Point2D(x=self.x,y=self.y)
|
return Point2D(x=self.x, y=self.y)
|
||||||
|
|
||||||
|
|
||||||
class Face:
|
class Face:
|
||||||
def __init__(self,a=0,b=0,c=0):
|
def __init__(self, a=0, b=0, c=0):
|
||||||
self.a = a
|
self.a = a
|
||||||
self.b = b
|
self.b = b
|
||||||
self.c = c
|
self.c = c
|
||||||
def string(self,prefix="f", indexOffset=0 ,textureoffset=0):
|
|
||||||
|
def string(self, prefix="f", indexOffset=0, textureoffset=0):
|
||||||
if textureoffset == 0:
|
if textureoffset == 0:
|
||||||
return prefix + ' {0}//{0} {1}//{1} {2}//{2}\n'.format(self.a + indexOffset, self.b + indexOffset, self.c + indexOffset)
|
return prefix + ' {0}//{0} {1}//{1} {2}//{2}\n'.format(self.a + indexOffset, self.b + indexOffset, self.c + indexOffset)
|
||||||
else:
|
else:
|
||||||
return prefix + ' {0}/{3}/{0} {1}/{4}/{1} {2}/{5}/{2}\n'.format(self.a + indexOffset, self.b + indexOffset, self.c + indexOffset,self.a + textureoffset, self.b + textureoffset, self.c + textureoffset)
|
return prefix + ' {0}/{3}/{0} {1}/{4}/{1} {2}/{5}/{2}\n'.format(
|
||||||
|
self.a + indexOffset,
|
||||||
|
self.b + indexOffset,
|
||||||
|
self.c + indexOffset,
|
||||||
|
self.a + textureoffset,
|
||||||
|
self.b + textureoffset,
|
||||||
|
self.c + textureoffset
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '[{0},{1},{2}]'.format(self.a, self.b, self.c)
|
return '[{0},{1},{2}]'.format(self.a, self.b, self.c)
|
||||||
|
|
||||||
|
|
||||||
class Group:
|
class Group:
|
||||||
def __init__(self, node):
|
def __init__(self, node):
|
||||||
self.partRefs = node.getAttribute('partRefs').split(',')
|
self.partRefs = node.getAttribute('partRefs').split(',')
|
||||||
|
|
||||||
|
|
||||||
class Bone:
|
class Bone:
|
||||||
def __init__(self, node):
|
def __init__(self, node):
|
||||||
self.refID = node.getAttribute('refID')
|
self.refID = node.getAttribute('refID')
|
||||||
(a, b, c, d, e, f, g, h, i, x, y, z) = map(float, node.getAttribute('transformation').split(','))
|
(a, b, c, d, e, f, g, h, i, x, y, z) = map(float, node.getAttribute('transformation').split(','))
|
||||||
self.matrix = Matrix3D(n11=a,n12=b,n13=c,n14=0,n21=d,n22=e,n23=f,n24=0,n31=g,n32=h,n33=i,n34=0,n41=x,n42=y,n43=z,n44=1)
|
self.matrix = Matrix3D(n11=a, n12=b, n13=c, n14=0, n21=d, n22=e, n23=f, n24=0, n31=g, n32=h, n33=i, n34=0, n41=x, n42=y, n43=z, n44=1)
|
||||||
|
|
||||||
|
|
||||||
class Part:
|
class Part:
|
||||||
def __init__(self, node):
|
def __init__(self, node):
|
||||||
@ -185,19 +200,17 @@ class Part:
|
|||||||
self.designID = node.getAttribute('designID')
|
self.designID = node.getAttribute('designID')
|
||||||
self.materials = list(map(str, node.getAttribute('materials').split(',')))
|
self.materials = list(map(str, node.getAttribute('materials').split(',')))
|
||||||
|
|
||||||
lastm = '0'
|
|
||||||
for i, m in enumerate(self.materials):
|
for i, m in enumerate(self.materials):
|
||||||
if (m == '0'):
|
if (m == '0'):
|
||||||
# self.materials[i] = lastm
|
# self.materials[i] = lastm
|
||||||
self.materials[i] = self.materials[0] #in case of 0 choose the 'base' material
|
self.materials[i] = self.materials[0] # in case of 0 choose the 'base' material
|
||||||
else:
|
|
||||||
lastm = m
|
|
||||||
if node.hasAttribute('decoration'):
|
if node.hasAttribute('decoration'):
|
||||||
self.decoration = list(map(str,node.getAttribute('decoration').split(',')))
|
self.decoration = list(map(str, node.getAttribute('decoration').split(',')))
|
||||||
for childnode in node.childNodes:
|
for childnode in node.childNodes:
|
||||||
if childnode.nodeName == 'Bone':
|
if childnode.nodeName == 'Bone':
|
||||||
self.Bones.append(Bone(node=childnode))
|
self.Bones.append(Bone(node=childnode))
|
||||||
|
|
||||||
|
|
||||||
class Brick:
|
class Brick:
|
||||||
def __init__(self, node):
|
def __init__(self, node):
|
||||||
self.refID = node.getAttribute('refID')
|
self.refID = node.getAttribute('refID')
|
||||||
@ -207,14 +220,16 @@ class Brick:
|
|||||||
if childnode.nodeName == 'Part':
|
if childnode.nodeName == 'Part':
|
||||||
self.Parts.append(Part(node=childnode))
|
self.Parts.append(Part(node=childnode))
|
||||||
|
|
||||||
|
|
||||||
class SceneCamera:
|
class SceneCamera:
|
||||||
def __init__(self, node):
|
def __init__(self, node):
|
||||||
self.refID = node.getAttribute('refID')
|
self.refID = node.getAttribute('refID')
|
||||||
(a, b, c, d, e, f, g, h, i, x, y, z) = map(float, node.getAttribute('transformation').split(','))
|
(a, b, c, d, e, f, g, h, i, x, y, z) = map(float, node.getAttribute('transformation').split(','))
|
||||||
self.matrix = Matrix3D(n11=a,n12=b,n13=c,n14=0,n21=d,n22=e,n23=f,n24=0,n31=g,n32=h,n33=i,n34=0,n41=x,n42=y,n43=z,n44=1)
|
self.matrix = Matrix3D(n11=a, n12=b, n13=c, n14=0, n21=d, n22=e, n23=f, n24=0, n31=g, n32=h, n33=i, n34=0, n41=x, n42=y, n43=z, n44=1)
|
||||||
self.fieldOfView = float(node.getAttribute('fieldOfView'))
|
self.fieldOfView = float(node.getAttribute('fieldOfView'))
|
||||||
self.distance = float(node.getAttribute('distance'))
|
self.distance = float(node.getAttribute('distance'))
|
||||||
|
|
||||||
|
|
||||||
class Scene:
|
class Scene:
|
||||||
def __init__(self, file):
|
def __init__(self, file):
|
||||||
self.Bricks = []
|
self.Bricks = []
|
||||||
@ -262,6 +277,7 @@ class Scene:
|
|||||||
|
|
||||||
# print('Scene "'+ self.Name + '" Brickversion: ' + str(self.Version))
|
# print('Scene "'+ self.Name + '" Brickversion: ' + str(self.Version))
|
||||||
|
|
||||||
|
|
||||||
class GeometryReader:
|
class GeometryReader:
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
self.offset = 0
|
self.offset = 0
|
||||||
@ -282,10 +298,10 @@ class GeometryReader:
|
|||||||
options = self.readInt()
|
options = self.readInt()
|
||||||
|
|
||||||
for i in range(0, self.valueCount):
|
for i in range(0, self.valueCount):
|
||||||
self.positions.append(Point3D(x=self.readFloat(),y= self.readFloat(),z=self.readFloat()))
|
self.positions.append(Point3D(x=self.readFloat(), y=self.readFloat(), z=self.readFloat()))
|
||||||
|
|
||||||
for i in range(0, self.valueCount):
|
for i in range(0, self.valueCount):
|
||||||
self.normals.append(Point3D(x=self.readFloat(),y= self.readFloat(),z=self.readFloat()))
|
self.normals.append(Point3D(x=self.readFloat(), y=self.readFloat(), z=self.readFloat()))
|
||||||
|
|
||||||
if (options & 3) == 3:
|
if (options & 3) == 3:
|
||||||
self.texCount = self.valueCount
|
self.texCount = self.valueCount
|
||||||
@ -293,7 +309,7 @@ class GeometryReader:
|
|||||||
self.textures.append(Point2D(x=self.readFloat(), y=self.readFloat()))
|
self.textures.append(Point2D(x=self.readFloat(), y=self.readFloat()))
|
||||||
|
|
||||||
for i in range(0, self.faceCount):
|
for i in range(0, self.faceCount):
|
||||||
self.faces.append(Face(a=self.readInt(),b=self.readInt(),c=self.readInt()))
|
self.faces.append(Face(a=self.readInt(), b=self.readInt(), c=self.readInt()))
|
||||||
|
|
||||||
if (options & 48) == 48:
|
if (options & 48) == 48:
|
||||||
num = self.readInt()
|
num = self.readInt()
|
||||||
@ -311,7 +327,7 @@ class GeometryReader:
|
|||||||
boneoffset = self.readInt() + 4
|
boneoffset = self.readInt() + 4
|
||||||
self.bonemap[i] = self.read_Int(datastart + boneoffset)
|
self.bonemap[i] = self.read_Int(datastart + boneoffset)
|
||||||
|
|
||||||
def read_Int(self,_offset):
|
def read_Int(self, _offset):
|
||||||
if sys.version_info < (3, 0):
|
if sys.version_info < (3, 0):
|
||||||
return int(struct.unpack_from('i', self.data, _offset)[0])
|
return int(struct.unpack_from('i', self.data, _offset)[0])
|
||||||
else:
|
else:
|
||||||
@ -330,6 +346,7 @@ class GeometryReader:
|
|||||||
self.offset += 4
|
self.offset += 4
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class Geometry:
|
class Geometry:
|
||||||
def __init__(self, designID, database):
|
def __init__(self, designID, database):
|
||||||
self.designID = designID
|
self.designID = designID
|
||||||
@ -337,21 +354,25 @@ class Geometry:
|
|||||||
self.maxGeoBounding = -1
|
self.maxGeoBounding = -1
|
||||||
self.studsFields2D = []
|
self.studsFields2D = []
|
||||||
|
|
||||||
GeometryLocation = '{0}{1}{2}'.format(GEOMETRIEPATH, designID,'.g')
|
GeometryLocation = '{0}{1}{2}'.format(GEOMETRIEPATH, designID, '.g')
|
||||||
GeometryCount = 0
|
GeometryCount = 0
|
||||||
while str(GeometryLocation) in database.filelist:
|
while str(GeometryLocation) in database.filelist:
|
||||||
self.Parts[GeometryCount] = GeometryReader(data=database.filelist[GeometryLocation].read())
|
self.Parts[GeometryCount] = GeometryReader(data=database.filelist[GeometryLocation].read())
|
||||||
GeometryCount += 1
|
GeometryCount += 1
|
||||||
GeometryLocation = '{0}{1}{2}{3}'.format(GEOMETRIEPATH, designID,'.g',GeometryCount)
|
GeometryLocation = '{0}{1}{2}{3}'.format(GEOMETRIEPATH, designID, '.g', GeometryCount)
|
||||||
|
|
||||||
primitive = Primitive(data = database.filelist[PRIMITIVEPATH + designID + '.xml'].read())
|
primitive = Primitive(data=database.filelist[PRIMITIVEPATH + designID + '.xml'].read())
|
||||||
self.Partname = primitive.Designname
|
self.Partname = primitive.Designname
|
||||||
self.studsFields2D = primitive.Fields2D
|
self.studsFields2D = primitive.Fields2D
|
||||||
try:
|
try:
|
||||||
geoBoundingList = [abs(float(primitive.Bounding['minX']) - float(primitive.Bounding['maxX'])), abs(float(primitive.Bounding['minY']) - float(primitive.Bounding['maxY'])), abs(float(primitive.Bounding['minZ']) - float(primitive.Bounding['maxZ']))]
|
geoBoundingList = [
|
||||||
|
abs(float(primitive.Bounding['minX']) - float(primitive.Bounding['maxX'])),
|
||||||
|
abs(float(primitive.Bounding['minY']) - float(primitive.Bounding['maxY'])),
|
||||||
|
abs(float(primitive.Bounding['minZ']) - float(primitive.Bounding['maxZ']))
|
||||||
|
]
|
||||||
geoBoundingList.sort()
|
geoBoundingList.sort()
|
||||||
self.maxGeoBounding = geoBoundingList[-1]
|
self.maxGeoBounding = geoBoundingList[-1]
|
||||||
except KeyError as e:
|
except KeyError:
|
||||||
# print('\nBounding errror in part {0}: {1}\n'.format(designID, e))
|
# print('\nBounding errror in part {0}: {1}\n'.format(designID, e))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -386,25 +407,33 @@ class Geometry:
|
|||||||
count += self.Parts[part].texCount
|
count += self.Parts[part].texCount
|
||||||
return count
|
return count
|
||||||
|
|
||||||
|
|
||||||
class Bone2:
|
class Bone2:
|
||||||
def __init__(self,boneId=0, angle=0, ax=0, ay=0, az=0, tx=0, ty=0, tz=0):
|
def __init__(self, boneId=0, angle=0, ax=0, ay=0, az=0, tx=0, ty=0, tz=0):
|
||||||
self.boneId = boneId
|
self.boneId = boneId
|
||||||
rotationMatrix = Matrix3D()
|
rotationMatrix = Matrix3D()
|
||||||
rotationMatrix.rotate(angle = -angle * math.pi / 180.0,axis = Point3D(x=ax,y=ay,z=az))
|
rotationMatrix.rotate(
|
||||||
p = Point3D(x=tx,y=ty,z=tz)
|
angle=(-angle * math.pi / 180.0),
|
||||||
|
axis=Point3D(x=ax, y=ay, z=az)
|
||||||
|
)
|
||||||
|
p = Point3D(x=tx, y=ty, z=tz)
|
||||||
p.transformW(rotationMatrix)
|
p.transformW(rotationMatrix)
|
||||||
rotationMatrix.n41 -= p.x
|
rotationMatrix.n41 -= p.x
|
||||||
rotationMatrix.n42 -= p.y
|
rotationMatrix.n42 -= p.y
|
||||||
rotationMatrix.n43 -= p.z
|
rotationMatrix.n43 -= p.z
|
||||||
self.matrix = rotationMatrix
|
self.matrix = rotationMatrix
|
||||||
|
|
||||||
|
|
||||||
class Field2D:
|
class Field2D:
|
||||||
def __init__(self, type=0, width=0, height=0, angle=0, ax=0, ay=0, az=0, tx=0, ty=0, tz=0, field2DRawData='none'):
|
def __init__(self, type=0, width=0, height=0, angle=0, ax=0, ay=0, az=0, tx=0, ty=0, tz=0, field2DRawData='none'):
|
||||||
self.type = type
|
self.type = type
|
||||||
self.field2DRawData = field2DRawData
|
self.field2DRawData = field2DRawData
|
||||||
rotationMatrix = Matrix3D()
|
rotationMatrix = Matrix3D()
|
||||||
rotationMatrix.rotate(angle = -angle * math.pi / 180.0, axis = Point3D(x=ax,y=ay,z=az))
|
rotationMatrix.rotate(
|
||||||
p = Point3D(x=tx,y=ty,z=tz)
|
angle=(-angle * math.pi / 180.0),
|
||||||
|
axis=Point3D(x=ax, y=ay, z=az)
|
||||||
|
)
|
||||||
|
p = Point3D(x=tx, y=ty, z=tz)
|
||||||
p.transformW(rotationMatrix)
|
p.transformW(rotationMatrix)
|
||||||
rotationMatrix.n41 -= p.x
|
rotationMatrix.n41 -= p.x
|
||||||
rotationMatrix.n42 -= p.y
|
rotationMatrix.n42 -= p.y
|
||||||
@ -413,7 +442,7 @@ class Field2D:
|
|||||||
self.matrix = rotationMatrix
|
self.matrix = rotationMatrix
|
||||||
self.custom2DField = []
|
self.custom2DField = []
|
||||||
|
|
||||||
#The height and width are always double the number of studs. The contained text is a 2D array that is always height + 1 and width + 1.
|
# The height and width are always double the number of studs. The contained text is a 2D array that is always height + 1 and width + 1.
|
||||||
rows_count = height + 1
|
rows_count = height + 1
|
||||||
cols_count = width + 1
|
cols_count = width + 1
|
||||||
# creation looks reverse
|
# creation looks reverse
|
||||||
@ -432,18 +461,23 @@ class Field2D:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '[type="{0}" transform="{1}" custom2DField="{2}"]'.format(self.type, self.matrix, self.custom2DField)
|
return '[type="{0}" transform="{1}" custom2DField="{2}"]'.format(self.type, self.matrix, self.custom2DField)
|
||||||
|
|
||||||
|
|
||||||
class CollisionBox:
|
class CollisionBox:
|
||||||
def __init__(self, sX=0, sY=0, sZ=0, angle=0, ax=0, ay=0, az=0, tx=0, ty=0, tz=0):
|
def __init__(self, sX=0, sY=0, sZ=0, angle=0, ax=0, ay=0, az=0, tx=0, ty=0, tz=0):
|
||||||
rotationMatrix = Matrix3D()
|
rotationMatrix = Matrix3D()
|
||||||
rotationMatrix.rotate(angle = -angle * math.pi / 180.0, axis = Point3D(x=ax,y=ay,z=az))
|
rotationMatrix.rotate(
|
||||||
p = Point3D(x=tx,y=ty,z=tz)
|
angle=(-angle * math.pi / 180.0),
|
||||||
|
axis=Point3D(x=ax, y=ay, z=az)
|
||||||
|
)
|
||||||
|
p = Point3D(x=tx, y=ty,
|
||||||
|
z=tz)
|
||||||
p.transformW(rotationMatrix)
|
p.transformW(rotationMatrix)
|
||||||
rotationMatrix.n41 -= p.x
|
rotationMatrix.n41 -= p.x
|
||||||
rotationMatrix.n42 -= p.y
|
rotationMatrix.n42 -= p.y
|
||||||
rotationMatrix.n43 -= p.z
|
rotationMatrix.n43 -= p.z
|
||||||
|
|
||||||
self.matrix = rotationMatrix
|
self.matrix = rotationMatrix
|
||||||
self.corner = Point3D(x=sX,y=sY,z=sZ)
|
self.corner = Point3D(x=sX, y=sY, z=sZ)
|
||||||
self.positions = []
|
self.positions = []
|
||||||
|
|
||||||
self.positions.append(Point3D(x=0, y=0, z=0))
|
self.positions.append(Point3D(x=0, y=0, z=0))
|
||||||
@ -452,11 +486,14 @@ class CollisionBox:
|
|||||||
self.positions.append(Point3D(x=sX, y=sY, z=0))
|
self.positions.append(Point3D(x=sX, y=sY, z=0))
|
||||||
self.positions.append(Point3D(x=0, y=0, z=sZ))
|
self.positions.append(Point3D(x=0, y=0, z=sZ))
|
||||||
self.positions.append(Point3D(x=0, y=sY, z=sZ))
|
self.positions.append(Point3D(x=0, y=sY, z=sZ))
|
||||||
self.positions.append(Point3D(x=sX ,y=0, z=sZ))
|
self.positions.append(Point3D(x=sX, y=0, z=sZ))
|
||||||
self.positions.append(Point3D(x=sX ,y=sY, z=sZ))
|
self.positions.append(Point3D(x=sX, y=sY, z=sZ))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '[0,0,0] [{0},0,0] [0,{1},0] [{0},{1},0] [0,0,{2}] [0,{1},{2}] [{0},0,{2}] [{0},{1},{2}]'.format(self.corner.x, self.corner.y, self.corner.z)
|
return '[0,0,0] [{0},0,0] [0,{1},0] [{0},{1},0] [0,0,{2}] [0,{1},{2}] [{0},0,{2}] [{0},{1},{2}]'.format(
|
||||||
|
self.corner.x, self.corner.y, self.corner.z
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Primitive:
|
class Primitive:
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
@ -475,7 +512,18 @@ class Primitive:
|
|||||||
if node.nodeName == 'Flex':
|
if node.nodeName == 'Flex':
|
||||||
for node in node.childNodes:
|
for node in node.childNodes:
|
||||||
if node.nodeName == 'Bone':
|
if node.nodeName == 'Bone':
|
||||||
self.Bones.append(Bone2(boneId=int(node.getAttribute('boneId')), angle=float(node.getAttribute('angle')), ax=float(node.getAttribute('ax')), ay=float(node.getAttribute('ay')), az=float(node.getAttribute('az')), tx=float(node.getAttribute('tx')), ty=float(node.getAttribute('ty')), tz=float(node.getAttribute('tz'))))
|
self.Bones.append(
|
||||||
|
Bone2(
|
||||||
|
boneId=int(node.getAttribute('boneId')),
|
||||||
|
angle=float(node.getAttribute('angle')),
|
||||||
|
ax=float(node.getAttribute('ax')),
|
||||||
|
ay=float(node.getAttribute('ay')),
|
||||||
|
az=float(node.getAttribute('az')),
|
||||||
|
tx=float(node.getAttribute('tx')),
|
||||||
|
ty=float(node.getAttribute('ty')),
|
||||||
|
tz=float(node.getAttribute('tz'))
|
||||||
|
)
|
||||||
|
)
|
||||||
elif node.nodeName == 'Annotations':
|
elif node.nodeName == 'Annotations':
|
||||||
for childnode in node.childNodes:
|
for childnode in node.childNodes:
|
||||||
if childnode.nodeName == 'Annotation' and childnode.hasAttribute('designname'):
|
if childnode.nodeName == 'Annotation' and childnode.hasAttribute('designname'):
|
||||||
@ -483,23 +531,73 @@ class Primitive:
|
|||||||
elif node.nodeName == 'Collision':
|
elif node.nodeName == 'Collision':
|
||||||
for childnode in node.childNodes:
|
for childnode in node.childNodes:
|
||||||
if childnode.nodeName == 'Box':
|
if childnode.nodeName == 'Box':
|
||||||
self.CollisionBoxes.append(CollisionBox(sX=float(childnode.getAttribute('sX')), sY=float(childnode.getAttribute('sY')), sZ=float(childnode.getAttribute('sZ')), angle=float(childnode.getAttribute('angle')), ax=float(childnode.getAttribute('ax')), ay=float(childnode.getAttribute('ay')), az=float(childnode.getAttribute('az')), tx=float(childnode.getAttribute('tx')), ty=float(childnode.getAttribute('ty')), tz=float(childnode.getAttribute('tz'))))
|
self.CollisionBoxes.append(
|
||||||
|
CollisionBox(
|
||||||
|
sX=float(childnode.getAttribute('sX')),
|
||||||
|
sY=float(childnode.getAttribute('sY')),
|
||||||
|
sZ=float(childnode.getAttribute('sZ')),
|
||||||
|
angle=float(childnode.getAttribute('angle')),
|
||||||
|
ax=float(childnode.getAttribute('ax')),
|
||||||
|
ay=float(childnode.getAttribute('ay')),
|
||||||
|
az=float(childnode.getAttribute('az')),
|
||||||
|
tx=float(childnode.getAttribute('tx')),
|
||||||
|
ty=float(childnode.getAttribute('ty')),
|
||||||
|
tz=float(childnode.getAttribute('tz'))
|
||||||
|
)
|
||||||
|
)
|
||||||
elif node.nodeName == 'PhysicsAttributes':
|
elif node.nodeName == 'PhysicsAttributes':
|
||||||
self.PhysicsAttributes = {"inertiaTensor": node.getAttribute('inertiaTensor'),"centerOfMass": node.getAttribute('centerOfMass'),"mass": node.getAttribute('mass'),"frictionType": node.getAttribute('frictionType')}
|
self.PhysicsAttributes = {
|
||||||
|
"inertiaTensor": node.getAttribute('inertiaTensor'),
|
||||||
|
"centerOfMass": node.getAttribute('centerOfMass'),
|
||||||
|
"mass": node.getAttribute('mass'),
|
||||||
|
"frictionType": node.getAttribute('frictionType')
|
||||||
|
}
|
||||||
elif node.nodeName == 'Bounding':
|
elif node.nodeName == 'Bounding':
|
||||||
for childnode in node.childNodes:
|
for childnode in node.childNodes:
|
||||||
if childnode.nodeName == 'AABB':
|
if childnode.nodeName == 'AABB':
|
||||||
self.Bounding = {"minX": childnode.getAttribute('minX'), "minY": childnode.getAttribute('minY'), "minZ": childnode.getAttribute('minZ'), "maxX": childnode.getAttribute('maxX'), "maxY": childnode.getAttribute('maxY'), "maxZ": childnode.getAttribute('maxZ')}
|
self.Bounding = {
|
||||||
|
"minX": childnode.getAttribute('minX'),
|
||||||
|
"minY": childnode.getAttribute('minY'),
|
||||||
|
"minZ": childnode.getAttribute('minZ'),
|
||||||
|
"maxX": childnode.getAttribute('maxX'),
|
||||||
|
"maxY": childnode.getAttribute('maxY'),
|
||||||
|
"maxZ": childnode.getAttribute('maxZ')
|
||||||
|
}
|
||||||
elif node.nodeName == 'GeometryBounding':
|
elif node.nodeName == 'GeometryBounding':
|
||||||
for childnode in node.childNodes:
|
for childnode in node.childNodes:
|
||||||
if childnode.nodeName == 'AABB':
|
if childnode.nodeName == 'AABB':
|
||||||
self.GeometryBounding = {"minX": childnode.getAttribute('minX'), "minY": childnode.getAttribute('minY'), "minZ": childnode.getAttribute('minZ'), "maxX": childnode.getAttribute('maxX'), "maxY": childnode.getAttribute('maxY'), "maxZ": childnode.getAttribute('maxZ')}
|
self.GeometryBounding = {
|
||||||
|
"minX": childnode.getAttribute('minX'),
|
||||||
|
"minY": childnode.getAttribute('minY'),
|
||||||
|
"minZ": childnode.getAttribute('minZ'),
|
||||||
|
"maxX": childnode.getAttribute('maxX'),
|
||||||
|
"maxY": childnode.getAttribute('maxY'),
|
||||||
|
"maxZ": childnode.getAttribute('maxZ')
|
||||||
|
}
|
||||||
elif node.nodeName == 'Connectivity':
|
elif node.nodeName == 'Connectivity':
|
||||||
for childnode in node.childNodes:
|
for childnode in node.childNodes:
|
||||||
if childnode.nodeName == 'Custom2DField':
|
if childnode.nodeName == 'Custom2DField':
|
||||||
self.Fields2D.append(Field2D(type=int(childnode.getAttribute('type')), width=int(childnode.getAttribute('width')), height=int(childnode.getAttribute('height')), angle=float(childnode.getAttribute('angle')), ax=float(childnode.getAttribute('ax')), ay=float(childnode.getAttribute('ay')), az=float(childnode.getAttribute('az')), tx=float(childnode.getAttribute('tx')), ty=float(childnode.getAttribute('ty')), tz=float(childnode.getAttribute('tz')), field2DRawData=str(childnode.firstChild.data)))
|
self.Fields2D.append(
|
||||||
|
Field2D(
|
||||||
|
type=int(childnode.getAttribute('type')),
|
||||||
|
width=int(childnode.getAttribute('width')),
|
||||||
|
height=int(childnode.getAttribute('height')),
|
||||||
|
angle=float(childnode.getAttribute('angle')),
|
||||||
|
ax=float(childnode.getAttribute('ax')),
|
||||||
|
ay=float(childnode.getAttribute('ay')),
|
||||||
|
az=float(childnode.getAttribute('az')),
|
||||||
|
tx=float(childnode.getAttribute('tx')),
|
||||||
|
ty=float(childnode.getAttribute('ty')),
|
||||||
|
tz=float(childnode.getAttribute('tz')),
|
||||||
|
field2DRawData=str(childnode.firstChild.data)
|
||||||
|
)
|
||||||
|
)
|
||||||
elif node.nodeName == 'Decoration':
|
elif node.nodeName == 'Decoration':
|
||||||
self.Decoration = {"faces": node.getAttribute('faces'), "subMaterialRedirectLookupTable": node.getAttribute('subMaterialRedirectLookupTable')}
|
self.Decoration = {
|
||||||
|
"faces": node.getAttribute('faces'),
|
||||||
|
"subMaterialRedirectLookupTable": node.getAttribute('subMaterialRedirectLookupTable')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Materials:
|
class Materials:
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
@ -514,13 +612,14 @@ class Materials:
|
|||||||
b=int(node.getAttribute('Blue')),
|
b=int(node.getAttribute('Blue')),
|
||||||
a=int(node.getAttribute('Alpha')),
|
a=int(node.getAttribute('Alpha')),
|
||||||
mtype=str(node.getAttribute('MaterialType'))
|
mtype=str(node.getAttribute('MaterialType'))
|
||||||
)
|
)
|
||||||
|
|
||||||
def getMaterialbyId(self, mid):
|
def getMaterialbyId(self, mid):
|
||||||
return self.Materials[mid]
|
return self.Materials[mid]
|
||||||
|
|
||||||
|
|
||||||
class Material:
|
class Material:
|
||||||
def __init__(self,id, r, g, b, a, mtype):
|
def __init__(self, id, r, g, b, a, mtype):
|
||||||
self.id = id
|
self.id = id
|
||||||
self.name = id
|
self.name = id
|
||||||
self.mattype = mtype
|
self.mattype = mtype
|
||||||
@ -528,18 +627,25 @@ class Material:
|
|||||||
self.g = float(g)
|
self.g = float(g)
|
||||||
self.b = float(b)
|
self.b = float(b)
|
||||||
self.a = float(a)
|
self.a = float(a)
|
||||||
|
|
||||||
def string(self):
|
def string(self):
|
||||||
out = 'Kd {0} {1} {2}\nKa 1.600000 1.600000 1.600000\nKs 0.400000 0.400000 0.400000\nNs 3.482202\nTf 1 1 1\n'.format( self.r / 255, self.g / 255,self.b / 255)
|
out = 'Kd {0} {1} {2}\nKa 1.600000 1.600000 1.600000\nKs 0.400000 0.400000 0.400000\nNs 3.482202\nTf 1 1 1\n'.format(
|
||||||
|
self.r / 255,
|
||||||
|
self.g / 255,
|
||||||
|
self.b / 255
|
||||||
|
)
|
||||||
if self.a < 255:
|
if self.a < 255:
|
||||||
out += 'Ni 1.575\n' + 'd {0}'.format(0.05) + '\n' + 'Tr {0}\n'.format(0.05)
|
out += 'Ni 1.575\n' + 'd {0}'.format(0.05) + '\n' + 'Tr {0}\n'.format(0.05)
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
class DBinfo:
|
class DBinfo:
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
xml = minidom.parseString(data)
|
xml = minidom.parseString(data)
|
||||||
self.Version = xml.getElementsByTagName('Bricks')[0].attributes['version'].value
|
self.Version = xml.getElementsByTagName('Bricks')[0].attributes['version'].value
|
||||||
# print('DB Version: ' + str(self.Version))
|
# print('DB Version: ' + str(self.Version))
|
||||||
|
|
||||||
|
|
||||||
class DBFolderFile:
|
class DBFolderFile:
|
||||||
def __init__(self, name, handle):
|
def __init__(self, name, handle):
|
||||||
self.handle = handle
|
self.handle = handle
|
||||||
@ -554,6 +660,7 @@ class DBFolderFile:
|
|||||||
finally:
|
finally:
|
||||||
reader.close()
|
reader.close()
|
||||||
|
|
||||||
|
|
||||||
class LIFFile:
|
class LIFFile:
|
||||||
def __init__(self, name, offset, size, handle):
|
def __init__(self, name, offset, size, handle):
|
||||||
self.handle = handle
|
self.handle = handle
|
||||||
@ -565,6 +672,7 @@ class LIFFile:
|
|||||||
self.handle.seek(self.offset, 0)
|
self.handle.seek(self.offset, 0)
|
||||||
return self.handle.read(self.size)
|
return self.handle.read(self.size)
|
||||||
|
|
||||||
|
|
||||||
class DBFolderReader:
|
class DBFolderReader:
|
||||||
def __init__(self, folder):
|
def __init__(self, folder):
|
||||||
self.filelist = {}
|
self.filelist = {}
|
||||||
@ -574,14 +682,14 @@ class DBFolderReader:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
os.path.isdir(self.location)
|
os.path.isdir(self.location)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
self.initok = False
|
self.initok = False
|
||||||
# print("db folder read FAIL")
|
# print("db folder read FAIL")
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self.parse()
|
self.parse()
|
||||||
if self.fileexist(os.path.join(self.location,'Materials.xml')) and self.fileexist(os.path.join(self.location, 'info.xml')):
|
if self.fileexist(os.path.join(self.location, 'Materials.xml')) and self.fileexist(os.path.join(self.location, 'info.xml')):
|
||||||
self.dbinfo = DBinfo(data=self.filelist[os.path.join(self.location,'info.xml')].read())
|
self.dbinfo = DBinfo(data=self.filelist[os.path.join(self.location, 'info.xml')].read())
|
||||||
# print("DB folder OK.")
|
# print("DB folder OK.")
|
||||||
self.initok = True
|
self.initok = True
|
||||||
else:
|
else:
|
||||||
@ -593,7 +701,6 @@ class DBFolderReader:
|
|||||||
# print(MATERIALNAMESPATH)
|
# print(MATERIALNAMESPATH)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def fileexist(self, filename):
|
def fileexist(self, filename):
|
||||||
return filename in self.filelist
|
return filename in self.filelist
|
||||||
|
|
||||||
@ -603,6 +710,7 @@ class DBFolderReader:
|
|||||||
entryName = os.path.join(path, name)
|
entryName = os.path.join(path, name)
|
||||||
self.filelist[entryName] = DBFolderFile(name=entryName, handle=entryName)
|
self.filelist[entryName] = DBFolderFile(name=entryName, handle=entryName)
|
||||||
|
|
||||||
|
|
||||||
class LIFReader:
|
class LIFReader:
|
||||||
def __init__(self, file):
|
def __init__(self, file):
|
||||||
self.packedFilesOffset = 84
|
self.packedFilesOffset = 84
|
||||||
@ -614,7 +722,7 @@ class LIFReader:
|
|||||||
try:
|
try:
|
||||||
self.filehandle = open(self.location, "rb")
|
self.filehandle = open(self.location, "rb")
|
||||||
self.filehandle.seek(0, 0)
|
self.filehandle.seek(0, 0)
|
||||||
except Exception as e:
|
except Exception:
|
||||||
self.initok = False
|
self.initok = False
|
||||||
# print("Database FAIL")
|
# print("Database FAIL")
|
||||||
return
|
return
|
||||||
@ -632,7 +740,7 @@ class LIFReader:
|
|||||||
# print("Database FAIL")
|
# print("Database FAIL")
|
||||||
self.initok = False
|
self.initok = False
|
||||||
|
|
||||||
def fileexist(self,filename):
|
def fileexist(self, filename):
|
||||||
return filename in self.filelist
|
return filename in self.filelist
|
||||||
|
|
||||||
def parse(self, prefix='', offset=0):
|
def parse(self, prefix='', offset=0):
|
||||||
@ -648,7 +756,7 @@ class LIFReader:
|
|||||||
entryType = self.readShort(offset=offset)
|
entryType = self.readShort(offset=offset)
|
||||||
offset += 6
|
offset += 6
|
||||||
|
|
||||||
entryName = '{0}{1}'.format(prefix,'/');
|
entryName = '{0}{1}'.format(prefix, '/')
|
||||||
self.filehandle.seek(offset + 1, 0)
|
self.filehandle.seek(offset + 1, 0)
|
||||||
if sys.version_info < (3, 0):
|
if sys.version_info < (3, 0):
|
||||||
t = ord(self.filehandle.read(1))
|
t = ord(self.filehandle.read(1))
|
||||||
@ -656,7 +764,7 @@ class LIFReader:
|
|||||||
t = int.from_bytes(self.filehandle.read(1), byteorder='big')
|
t = int.from_bytes(self.filehandle.read(1), byteorder='big')
|
||||||
|
|
||||||
while not t == 0:
|
while not t == 0:
|
||||||
entryName ='{0}{1}'.format(entryName,chr(t))
|
entryName = '{0}{1}'.format(entryName, chr(t))
|
||||||
self.filehandle.seek(1, 1)
|
self.filehandle.seek(1, 1)
|
||||||
if sys.version_info < (3, 0):
|
if sys.version_info < (3, 0):
|
||||||
t = ord(self.filehandle.read(1))
|
t = ord(self.filehandle.read(1))
|
||||||
@ -692,33 +800,32 @@ class LIFReader:
|
|||||||
else:
|
else:
|
||||||
return int.from_bytes(self.filehandle.read(2), byteorder='big')
|
return int.from_bytes(self.filehandle.read(2), byteorder='big')
|
||||||
|
|
||||||
|
|
||||||
class Converter:
|
class Converter:
|
||||||
def LoadDBFolder(self, dbfolderlocation):
|
def LoadDBFolder(self, dbfolderlocation):
|
||||||
self.database = DBFolderReader(folder=dbfolderlocation)
|
self.database = DBFolderReader(folder=dbfolderlocation)
|
||||||
if self.database.initok and self.database.fileexist(os.path.join(dbfolderlocation,'Materials.xml')):
|
if self.database.initok and self.database.fileexist(os.path.join(dbfolderlocation, 'Materials.xml')):
|
||||||
self.allMaterials = Materials(data=self.database.filelist[os.path.join(dbfolderlocation,'Materials.xml')].read());
|
self.allMaterials = Materials(data=self.database.filelist[os.path.join(dbfolderlocation, 'Materials.xml')].read())
|
||||||
|
|
||||||
def LoadDatabase(self,databaselocation):
|
def LoadDatabase(self, databaselocation):
|
||||||
self.database = LIFReader(file=databaselocation)
|
self.database = LIFReader(file=databaselocation)
|
||||||
|
|
||||||
if self.database.initok and self.database.fileexist('/Materials.xml'):
|
if self.database.initok and self.database.fileexist('/Materials.xml'):
|
||||||
self.allMaterials = Materials(data=self.database.filelist['/Materials.xml'].read());
|
self.allMaterials = Materials(data=self.database.filelist['/Materials.xml'].read())
|
||||||
|
|
||||||
def LoadScene(self,filename):
|
def LoadScene(self, filename):
|
||||||
if self.database.initok:
|
if self.database.initok:
|
||||||
self.scene = Scene(file=filename)
|
self.scene = Scene(file=filename)
|
||||||
|
|
||||||
def Export(self,filename):
|
def Export(self, filename):
|
||||||
invert = Matrix3D()
|
invert = Matrix3D()
|
||||||
#invert.n33 = -1 #uncomment to invert the Z-Axis
|
# invert.n33 = -1 #uncomment to invert the Z-Axis
|
||||||
|
|
||||||
indexOffset = 1
|
indexOffset = 1
|
||||||
textOffset = 1
|
textOffset = 1
|
||||||
usedmaterials = []
|
usedmaterials = []
|
||||||
geometriecache = {}
|
geometriecache = {}
|
||||||
|
|
||||||
start_time = time.time()
|
|
||||||
|
|
||||||
out = open(filename + ".obj.tmp", "w+")
|
out = open(filename + ".obj.tmp", "w+")
|
||||||
out.truncate(0)
|
out.truncate(0)
|
||||||
out.write("mtllib " + filename + ".mtl" + '\n\n')
|
out.write("mtllib " + filename + ".mtl" + '\n\n')
|
||||||
@ -735,12 +842,12 @@ class Converter:
|
|||||||
|
|
||||||
if pa.designID not in geometriecache:
|
if pa.designID not in geometriecache:
|
||||||
geo = Geometry(designID=pa.designID, database=self.database)
|
geo = Geometry(designID=pa.designID, database=self.database)
|
||||||
progress(current ,total , "(" + geo.designID + ") " + geo.Partname, ' ')
|
progress(current, total, "(" + geo.designID + ") " + geo.Partname, ' ')
|
||||||
geometriecache[pa.designID] = geo
|
geometriecache[pa.designID] = geo
|
||||||
else:
|
else:
|
||||||
geo = geometriecache[pa.designID]
|
geo = geometriecache[pa.designID]
|
||||||
|
|
||||||
progress(current ,total , "(" + geo.designID + ") " + geo.Partname ,'-')
|
progress(current, total, "(" + geo.designID + ") " + geo.Partname, '-')
|
||||||
|
|
||||||
out.write("o\n")
|
out.write("o\n")
|
||||||
|
|
||||||
@ -752,11 +859,11 @@ class Converter:
|
|||||||
# positions
|
# positions
|
||||||
for j, p in enumerate(geo.Parts[part].outpositions):
|
for j, p in enumerate(geo.Parts[part].outpositions):
|
||||||
if (geo.Parts[part].bonemap[j] == i):
|
if (geo.Parts[part].bonemap[j] == i):
|
||||||
p.transform( invert * b.matrix)
|
p.transform(invert * b.matrix)
|
||||||
# normals
|
# normals
|
||||||
for k, n in enumerate(geo.Parts[part].outnormals):
|
for k, n in enumerate(geo.Parts[part].outnormals):
|
||||||
if (geo.Parts[part].bonemap[k] == i):
|
if (geo.Parts[part].bonemap[k] == i):
|
||||||
n.transformW( invert * b.matrix)
|
n.transformW(invert * b.matrix)
|
||||||
|
|
||||||
for point in geo.Parts[part].outpositions:
|
for point in geo.Parts[part].outpositions:
|
||||||
out.write(point.string("v"))
|
out.write(point.string("v"))
|
||||||
@ -772,13 +879,12 @@ class Converter:
|
|||||||
last_color = 0
|
last_color = 0
|
||||||
for part in geo.Parts:
|
for part in geo.Parts:
|
||||||
|
|
||||||
|
# try catch here for possible problems in materials assignment of various g, g1, g2, .. files in lxf file
|
||||||
#try catch here for possible problems in materials assignment of various g, g1, g2, .. files in lxf file
|
|
||||||
try:
|
try:
|
||||||
materialCurrentPart = pa.materials[part]
|
materialCurrentPart = pa.materials[part]
|
||||||
last_color = pa.materials[part]
|
last_color = pa.materials[part]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# print('WARNING: {0}.g{1} has NO material assignment in lxf. Replaced with color {2}. Fix {0}.xml faces values.'.format(pa.designID, part, last_color))
|
|
||||||
materialCurrentPart = last_color
|
materialCurrentPart = last_color
|
||||||
|
|
||||||
lddmat = self.allMaterials.getMaterialbyId(materialCurrentPart)
|
lddmat = self.allMaterials.getMaterialbyId(materialCurrentPart)
|
||||||
@ -786,7 +892,7 @@ class Converter:
|
|||||||
|
|
||||||
deco = '0'
|
deco = '0'
|
||||||
if hasattr(pa, 'decoration') and len(geo.Parts[part].textures) > 0:
|
if hasattr(pa, 'decoration') and len(geo.Parts[part].textures) > 0:
|
||||||
#if decoCount <= len(pa.decoration):
|
# if decoCount <= len(pa.decoration):
|
||||||
if decoCount < len(pa.decoration):
|
if decoCount < len(pa.decoration):
|
||||||
deco = pa.decoration[decoCount]
|
deco = pa.decoration[decoCount]
|
||||||
decoCount += 1
|
decoCount += 1
|
||||||
@ -801,7 +907,7 @@ class Converter:
|
|||||||
f.write(self.database.filelist[decofilename].read())
|
f.write(self.database.filelist[decofilename].read())
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
if not matname in usedmaterials:
|
if matname not in usedmaterials:
|
||||||
usedmaterials.append(matname)
|
usedmaterials.append(matname)
|
||||||
outtext.write("newmtl " + matname + '\n')
|
outtext.write("newmtl " + matname + '\n')
|
||||||
outtext.write(lddmat.string())
|
outtext.write(lddmat.string())
|
||||||
@ -811,9 +917,9 @@ class Converter:
|
|||||||
out.write("usemtl " + matname + '\n')
|
out.write("usemtl " + matname + '\n')
|
||||||
for face in geo.Parts[part].faces:
|
for face in geo.Parts[part].faces:
|
||||||
if len(geo.Parts[part].textures) > 0:
|
if len(geo.Parts[part].textures) > 0:
|
||||||
out.write(face.string("f",indexOffset,textOffset))
|
out.write(face.string("f", indexOffset, textOffset))
|
||||||
else:
|
else:
|
||||||
out.write(face.string("f",indexOffset))
|
out.write(face.string("f", indexOffset))
|
||||||
|
|
||||||
indexOffset += len(geo.Parts[part].outpositions)
|
indexOffset += len(geo.Parts[part].outpositions)
|
||||||
textOffset += len(geo.Parts[part].textures)
|
textOffset += len(geo.Parts[part].textures)
|
||||||
@ -825,6 +931,7 @@ class Converter:
|
|||||||
sys.stdout.write('%s\r' % (' '))
|
sys.stdout.write('%s\r' % (' '))
|
||||||
# print("--- %s seconds ---" % (time.time() - start_time))
|
# print("--- %s seconds ---" % (time.time() - start_time))
|
||||||
|
|
||||||
|
|
||||||
def setDBFolderVars(dbfolderlocation, lod):
|
def setDBFolderVars(dbfolderlocation, lod):
|
||||||
global PRIMITIVEPATH
|
global PRIMITIVEPATH
|
||||||
global GEOMETRIEPATH
|
global GEOMETRIEPATH
|
||||||
@ -836,44 +943,8 @@ def setDBFolderVars(dbfolderlocation, lod):
|
|||||||
MATERIALNAMESPATH = os.path.join(dbfolderlocation, 'MaterialNames', '')
|
MATERIALNAMESPATH = os.path.join(dbfolderlocation, 'MaterialNames', '')
|
||||||
# print(MATERIALNAMESPATH)
|
# print(MATERIALNAMESPATH)
|
||||||
|
|
||||||
def FindDatabase():
|
|
||||||
lddliftree = os.getenv('LDDLIFTREE')
|
|
||||||
if lddliftree is not None:
|
|
||||||
if os.path.isdir(str(lddliftree)): #LDDLIFTREE points to folder
|
|
||||||
return str(lddliftree)
|
|
||||||
elif os.path.isfile(str(lddliftree)): #LDDLIFTREE points to file (should be db.lif)
|
|
||||||
return str(lddliftree)
|
|
||||||
|
|
||||||
else: #Env variable LDDLIFTREE not set. Check for default locations per different platform.
|
def progress(count, total, status='', suffix=''):
|
||||||
if platform.system() == 'Darwin':
|
|
||||||
if os.path.isdir(str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'Library','Application Support','LEGO Company','LEGO Digital Designer','db'))):
|
|
||||||
return str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'Library','Application Support','LEGO Company','LEGO Digital Designer','db'))
|
|
||||||
elif os.path.isfile(str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'Library','Application Support','LEGO Company','LEGO Digital Designer','db.lif'))):
|
|
||||||
return str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'Library','Application Support','LEGO Company','LEGO Digital Designer','db.lif'))
|
|
||||||
else:
|
|
||||||
# print("no LDD database found please install LEGO-Digital-Designer")
|
|
||||||
os._exit()
|
|
||||||
elif platform.system() == 'Windows':
|
|
||||||
if os.path.isdir(str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'AppData','Roaming','LEGO Company','LEGO Digital Designer','db'))):
|
|
||||||
return str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'AppData','Roaming','LEGO Company','LEGO Digital Designer','db'))
|
|
||||||
elif os.path.isfile(str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'AppData','Roaming','LEGO Company','LEGO Digital Designer','db.lif'))):
|
|
||||||
return str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'AppData','Roaming','LEGO Company','LEGO Digital Designer','db.lif'))
|
|
||||||
else:
|
|
||||||
# print("no LDD database found please install LEGO-Digital-Designer")
|
|
||||||
os._exit()
|
|
||||||
elif platform.system() == 'Linux':
|
|
||||||
if os.path.isdir(str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'.wine','drive_c','users',os.getenv('USER'),'Application Data','LEGO Company','LEGO Digital Designer','db'))):
|
|
||||||
return str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'.wine','drive_c','users',os.getenv('USER'),'Application Data','LEGO Company','LEGO Digital Designer','db'))
|
|
||||||
elif os.path.isfile(str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'.wine','drive_c','users',os.getenv('USER'),'Application Data','LEGO Company','LEGO Digital Designer','db.lif'))):
|
|
||||||
return str(os.path.join(str(os.getenv('USERPROFILE') or os.getenv('HOME')),'.wine','drive_c','users',os.getenv('USER'),'Application Data','LEGO Company','LEGO Digital Designer','db.lif'))
|
|
||||||
else:
|
|
||||||
# print("no LDD database found please install LEGO-Digital-Designer")
|
|
||||||
os._exit()
|
|
||||||
else:
|
|
||||||
# print('Your OS {0} is not supported yet.'.format(platform.system()))
|
|
||||||
os._exit()
|
|
||||||
|
|
||||||
def progress(count, total, status='', suffix = ''):
|
|
||||||
bar_len = 40
|
bar_len = 40
|
||||||
filled_len = int(round(bar_len * count / float(total)))
|
filled_len = int(round(bar_len * count / float(total)))
|
||||||
percents = round(100.0 * count / float(total), 1)
|
percents = round(100.0 * count / float(total), 1)
|
||||||
@ -882,6 +953,7 @@ def progress(count, total, status='', suffix = ''):
|
|||||||
sys.stdout.write('Progress: [%s] %s%s %s %s\r' % (bar, percents, '%', suffix, status))
|
sys.stdout.write('Progress: [%s] %s%s %s %s\r' % (bar, percents, '%', suffix, status))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
def main(lxf_filename, obj_filename, lod="2"):
|
def main(lxf_filename, obj_filename, lod="2"):
|
||||||
# print("- - - pylddlib - - -")
|
# print("- - - pylddlib - - -")
|
||||||
# print(" _ ")
|
# print(" _ ")
|
||||||
@ -896,10 +968,11 @@ def main(lxf_filename, obj_filename, lod="2"):
|
|||||||
GEOMETRIEPATH = GEOMETRIEPATH + f"LOD{lod}/"
|
GEOMETRIEPATH = GEOMETRIEPATH + f"LOD{lod}/"
|
||||||
converter = Converter()
|
converter = Converter()
|
||||||
# print("Found DB folder. Will use this instead of db.lif!")
|
# print("Found DB folder. Will use this instead of db.lif!")
|
||||||
setDBFolderVars(dbfolderlocation = "app/luclient/res/", lod=lod)
|
setDBFolderVars(dbfolderlocation="app/luclient/res/", lod=lod)
|
||||||
converter.LoadDBFolder(dbfolderlocation = "app/luclient/res/")
|
converter.LoadDBFolder(dbfolderlocation="app/luclient/res/")
|
||||||
converter.LoadScene(filename=lxf_filename)
|
converter.LoadScene(filename=lxf_filename)
|
||||||
converter.Export(filename=obj_filename)
|
converter.Export(filename=obj_filename)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
from flask import render_template, Blueprint, redirect, url_for, request, abort, flash, request, current_app
|
from flask import render_template, Blueprint, current_app
|
||||||
from flask_user import login_required, current_user
|
from flask_user import login_required
|
||||||
from app.models import db, CharacterInfo, Account, CharacterXML, Reports
|
from app.models import CharacterInfo, Account, CharacterXML, Reports
|
||||||
from app import gm_level, scheduler
|
from app import gm_level, scheduler
|
||||||
import datetime, xmltodict, json
|
import datetime
|
||||||
|
import xmltodict
|
||||||
|
|
||||||
reports_blueprint = Blueprint('reports', __name__)
|
reports_blueprint = Blueprint('reports', __name__)
|
||||||
|
|
||||||
|
|
||||||
@reports_blueprint.route('/', methods=['GET', 'POST'])
|
@reports_blueprint.route('/', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
@ -13,25 +15,28 @@ def index():
|
|||||||
reports = Reports.query.distinct(Reports.date).group_by(Reports.date).all()
|
reports = Reports.query.distinct(Reports.date).group_by(Reports.date).all()
|
||||||
return render_template('reports/index.html.j2', reports=reports)
|
return render_template('reports/index.html.j2', reports=reports)
|
||||||
|
|
||||||
|
|
||||||
@reports_blueprint.route('/items/by_date/<date>', methods=['GET', 'POST'])
|
@reports_blueprint.route('/items/by_date/<date>', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
def items_by_date(date):
|
def items_by_date(date):
|
||||||
data = Reports.query.filter(Reports.date==date).filter(Reports.report_type=="items").first().data
|
data = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "items").first().data
|
||||||
return render_template('reports/items/by_date.html.j2', data=data, date=date)
|
return render_template('reports/items/by_date.html.j2', data=data, date=date)
|
||||||
|
|
||||||
|
|
||||||
@reports_blueprint.route('/currency/by_date/<date>', methods=['GET', 'POST'])
|
@reports_blueprint.route('/currency/by_date/<date>', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
def currency_by_date(date):
|
def currency_by_date(date):
|
||||||
data = Reports.query.filter(Reports.date==date).filter(Reports.report_type=="currency").first().data
|
data = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "currency").first().data
|
||||||
return render_template('reports/currency/by_date.html.j2', data=data, date=date)
|
return render_template('reports/currency/by_date.html.j2', data=data, date=date)
|
||||||
|
|
||||||
|
|
||||||
@reports_blueprint.route('/uscore/by_date/<date>', methods=['GET', 'POST'])
|
@reports_blueprint.route('/uscore/by_date/<date>', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
@gm_level(3)
|
@gm_level(3)
|
||||||
def uscore_by_date(date):
|
def uscore_by_date(date):
|
||||||
data = Reports.query.filter(Reports.date==date).filter(Reports.report_type=="uscore").first().data
|
data = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "uscore").first().data
|
||||||
return render_template('reports/uscore/by_date.html.j2', data=data, date=date)
|
return render_template('reports/uscore/by_date.html.j2', data=data, date=date)
|
||||||
|
|
||||||
|
|
||||||
@ -42,22 +47,22 @@ def gen_item_report():
|
|||||||
current_app.logger.info("Start Item Report Generation")
|
current_app.logger.info("Start Item Report Generation")
|
||||||
|
|
||||||
date = datetime.date.today().strftime('%Y-%m-%d')
|
date = datetime.date.today().strftime('%Y-%m-%d')
|
||||||
report = Reports.query.filter(Reports.date==date).filter(Reports.report_type=="items").first()
|
report = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "items").first()
|
||||||
|
|
||||||
# Only one report per day
|
# Only one report per day
|
||||||
if report != None:
|
if report not None:
|
||||||
current_app.logger.info(f"Item Report Already Generated for {date}")
|
current_app.logger.info(f"Item Report Already Generated for {date}")
|
||||||
return
|
return
|
||||||
|
|
||||||
char_xmls = CharacterXML.query.join(
|
char_xmls = CharacterXML.query.join(
|
||||||
CharacterInfo,
|
CharacterInfo,
|
||||||
CharacterInfo.id==CharacterXML.id
|
CharacterInfo.id == CharacterXML.id
|
||||||
).join(
|
).join(
|
||||||
Account,
|
Account,
|
||||||
CharacterInfo.account_id==Account.id
|
CharacterInfo.account_id == Account.id
|
||||||
).filter(Account.gm_level < 3).all()
|
).filter(Account.gm_level < 3).all()
|
||||||
|
|
||||||
report_data={}
|
report_data = {}
|
||||||
|
|
||||||
for char_xml in char_xmls:
|
for char_xml in char_xmls:
|
||||||
try:
|
try:
|
||||||
@ -66,7 +71,7 @@ def gen_item_report():
|
|||||||
attr_prefix="attr_"
|
attr_prefix="attr_"
|
||||||
)
|
)
|
||||||
for inv in character_json["obj"]["inv"]["items"]["in"]:
|
for inv in character_json["obj"]["inv"]["items"]["in"]:
|
||||||
if "i" in inv.keys() and type(inv["i"]) == list and (int(inv["attr_t"])==0 or int(inv["attr_t"])==1):
|
if "i" in inv.keys() and type(inv["i"]) == list and (int(inv["attr_t"]) == 0 or int(inv["attr_t"]) == 1):
|
||||||
for item in inv["i"]:
|
for item in inv["i"]:
|
||||||
if item["attr_l"] in report_data:
|
if item["attr_l"] in report_data:
|
||||||
report_data[item["attr_l"]] = report_data[item["attr_l"]] + int(item["attr_c"])
|
report_data[item["attr_l"]] = report_data[item["attr_l"]] + int(item["attr_c"])
|
||||||
@ -96,22 +101,22 @@ def gen_currency_report():
|
|||||||
current_app.logger.info("Start Currency Report Generation")
|
current_app.logger.info("Start Currency Report Generation")
|
||||||
|
|
||||||
date = datetime.date.today().strftime('%Y-%m-%d')
|
date = datetime.date.today().strftime('%Y-%m-%d')
|
||||||
report = Reports.query.filter(Reports.date==date).filter(Reports.report_type=="currency").first()
|
report = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "currency").first()
|
||||||
|
|
||||||
# Only one report per day
|
# Only one report per day
|
||||||
if report != None:
|
if report not None:
|
||||||
current_app.logger.info(f"Currency Report Already Generated for {date}")
|
current_app.logger.info(f"Currency Report Already Generated for {date}")
|
||||||
return
|
return
|
||||||
|
|
||||||
characters = CharacterXML.query.join(
|
characters = CharacterXML.query.join(
|
||||||
CharacterInfo,
|
CharacterInfo,
|
||||||
CharacterInfo.id==CharacterXML.id
|
CharacterInfo.id == CharacterXML.id
|
||||||
).join(
|
).join(
|
||||||
Account,
|
Account,
|
||||||
CharacterInfo.account_id==Account.id
|
CharacterInfo.account_id == Account.id
|
||||||
).filter(Account.gm_level < 3).all()
|
).filter(Account.gm_level < 3).all()
|
||||||
|
|
||||||
report_data={}
|
report_data = {}
|
||||||
|
|
||||||
for character in characters:
|
for character in characters:
|
||||||
try:
|
try:
|
||||||
@ -119,7 +124,7 @@ def gen_currency_report():
|
|||||||
character.xml_data,
|
character.xml_data,
|
||||||
attr_prefix="attr_"
|
attr_prefix="attr_"
|
||||||
)
|
)
|
||||||
report_data[CharacterInfo.query.filter(CharacterInfo.id==character.id).first().name] = int(character_json["obj"]["char"]["attr_cc"])
|
report_data[CharacterInfo.query.filter(CharacterInfo.id == character.id).first().name] = int(character_json["obj"]["char"]["attr_cc"])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
current_app.logger.error(f"REPORT::CURRENCY - ERROR PARSING CHARACTER {char_xml.id}")
|
current_app.logger.error(f"REPORT::CURRENCY - ERROR PARSING CHARACTER {char_xml.id}")
|
||||||
current_app.logger.error(f"REPORT::CURRENCY - {e}")
|
current_app.logger.error(f"REPORT::CURRENCY - {e}")
|
||||||
@ -144,22 +149,22 @@ def gen_uscore_report():
|
|||||||
current_app.logger.info("Start U-Score Report Generation")
|
current_app.logger.info("Start U-Score Report Generation")
|
||||||
|
|
||||||
date = datetime.date.today().strftime('%Y-%m-%d')
|
date = datetime.date.today().strftime('%Y-%m-%d')
|
||||||
report = Reports.query.filter(Reports.date==date).filter(Reports.report_type=="uscore").first()
|
report = Reports.query.filter(Reports.date == date).filter(Reports.report_type == "uscore").first()
|
||||||
|
|
||||||
# Only one report per day
|
# Only one report per day
|
||||||
if report != None:
|
if report not None:
|
||||||
current_app.logger.info(f"U-Score Report Already Generated for {date}")
|
current_app.logger.info(f"U-Score Report Already Generated for {date}")
|
||||||
return
|
return
|
||||||
|
|
||||||
characters = CharacterXML.query.join(
|
characters = CharacterXML.query.join(
|
||||||
CharacterInfo,
|
CharacterInfo,
|
||||||
CharacterInfo.id==CharacterXML.id
|
CharacterInfo.id == CharacterXML.id
|
||||||
).join(
|
).join(
|
||||||
Account,
|
Account,
|
||||||
CharacterInfo.account_id==Account.id
|
CharacterInfo.account_id == Account.id
|
||||||
).filter(Account.gm_level < 3).all()
|
).filter(Account.gm_level < 3).all()
|
||||||
|
|
||||||
report_data={}
|
report_data = {}
|
||||||
|
|
||||||
for character in characters:
|
for character in characters:
|
||||||
try:
|
try:
|
||||||
@ -167,7 +172,7 @@ def gen_uscore_report():
|
|||||||
character.xml_data,
|
character.xml_data,
|
||||||
attr_prefix="attr_"
|
attr_prefix="attr_"
|
||||||
)
|
)
|
||||||
report_data[CharacterInfo.query.filter(CharacterInfo.id==character.id).first().name] = int(character_json["obj"]["char"]["attr_ls"])
|
report_data[CharacterInfo.query.filter(CharacterInfo.id == character.id).first().name] = int(character_json["obj"]["char"]["attr_ls"])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
current_app.logger.error(f"REPORT::U-SCORE - ERROR PARSING CHARACTER {char_xml.id}")
|
current_app.logger.error(f"REPORT::U-SCORE - ERROR PARSING CHARACTER {char_xml.id}")
|
||||||
current_app.logger.error(f"REPORT::U-SCORE - {e}")
|
current_app.logger.error(f"REPORT::U-SCORE - {e}")
|
||||||
|
@ -1,7 +1,21 @@
|
|||||||
from flask_marshmallow import Marshmallow
|
from flask_marshmallow import Marshmallow
|
||||||
from app.models import *
|
from app.models import (
|
||||||
|
PlayKey
|
||||||
|
PetNames
|
||||||
|
Mail
|
||||||
|
UGC
|
||||||
|
PropertyContent
|
||||||
|
Property
|
||||||
|
CharacterXML
|
||||||
|
CharacterInfo
|
||||||
|
Account
|
||||||
|
AccountInvitation
|
||||||
|
ActivityLog
|
||||||
|
CommandLog
|
||||||
|
)
|
||||||
ma = Marshmallow()
|
ma = Marshmallow()
|
||||||
|
|
||||||
|
|
||||||
class PlayKeySchema(ma.SQLAlchemyAutoSchema):
|
class PlayKeySchema(ma.SQLAlchemyAutoSchema):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PlayKey
|
model = PlayKey
|
||||||
@ -44,7 +58,6 @@ class PropertyContentSchema(ma.SQLAlchemyAutoSchema):
|
|||||||
ugc = ma.Nested(UGCSchema)
|
ugc = ma.Nested(UGCSchema)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PropertySchema(ma.SQLAlchemyAutoSchema):
|
class PropertySchema(ma.SQLAlchemyAutoSchema):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Property
|
model = Property
|
||||||
|
6
pylama.ini
Normal file
6
pylama.ini
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[pylama]
|
||||||
|
ignore = D203, D212, D213, D406, D407, D408, D409, D100, D104, D401, F722
|
||||||
|
max_line_length = 160
|
||||||
|
|
||||||
|
[pylama:mccabe]
|
||||||
|
max-complexity = 35
|
Loading…
Reference in New Issue
Block a user