Compare commits
126 Commits
v2.16.0
...
v2.19.1dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
098b088da6 | ||
|
|
14d62f31e1 | ||
|
|
e7b1f55d08 | ||
|
|
8f501896a1 | ||
|
|
befcb9b874 | ||
|
|
c70afa9a4c | ||
|
|
029c7dd4c2 | ||
|
|
1f83dba1ac | ||
|
|
6eae3405fd | ||
|
|
c0e1d9e4de | ||
|
|
7c0bd7aa88 | ||
|
|
394583584c | ||
|
|
4112e2aa6b | ||
|
|
aa19e0da72 | ||
|
|
bba9be1598 | ||
|
|
17998916b4 | ||
|
|
543089bcd9 | ||
|
|
7f35c78a65 | ||
|
|
b25798dd83 | ||
|
|
744b9ff78a | ||
|
|
8dc1457ebb | ||
|
|
982ad54fab | ||
|
|
912192cd7d | ||
|
|
74cd6d48da | ||
|
|
3467a7fe3f | ||
|
|
eb269a05ed | ||
|
|
c63cf4b3b0 | ||
|
|
11ed94454d | ||
|
|
8df07645da | ||
|
|
5666fdd250 | ||
|
|
0b55ae40fc | ||
|
|
3726e84697 | ||
|
|
a0c4341102 | ||
|
|
cd6b1038e8 | ||
|
|
10583fd506 | ||
|
|
713694be56 | ||
|
|
f50293cf77 | ||
|
|
7c88fa477f | ||
|
|
f8df540fad | ||
|
|
61a01805cc | ||
|
|
a93915cf04 | ||
|
|
0f74c97fbf | ||
|
|
29713b69dc | ||
|
|
cc3c2cb9c8 | ||
|
|
b36a3959da | ||
|
|
3b26bfc0e9 | ||
|
|
c59b621963 | ||
|
|
977a8fa329 | ||
|
|
a5226fee83 | ||
|
|
e4069a3988 | ||
|
|
6527f9e11e | ||
|
|
9ddfcc894f | ||
|
|
f22a4f13e5 | ||
|
|
fc9337df67 | ||
|
|
98a8332cfa | ||
|
|
a78eedad48 | ||
|
|
85e1a1bd06 | ||
|
|
25b2c04309 | ||
|
|
54a84d0e42 | ||
|
|
af0a4d1def | ||
|
|
97cdde84ce | ||
|
|
a65129b277 | ||
|
|
3b40a49918 | ||
|
|
d95345b476 | ||
|
|
2ba2d95017 | ||
|
|
4d0ffedcc8 | ||
|
|
84abde4fc5 | ||
|
|
8897f1e4b1 | ||
|
|
6f33cacb7a | ||
|
|
b1a8c0ad09 | ||
|
|
13ed635803 | ||
|
|
5a44909ebf | ||
|
|
6cbb80693d | ||
|
|
0b90d254f9 | ||
|
|
641d36205c | ||
|
|
6e38b6ea4d | ||
|
|
84b4d8fabb | ||
|
|
c0e1f7e746 | ||
|
|
d734c12168 | ||
|
|
340d94eb3e | ||
|
|
9b0b31648c | ||
|
|
8346358c37 | ||
|
|
b935700a12 | ||
|
|
2f4a5a4830 | ||
|
|
e951ce8e9d | ||
|
|
fc6d42f483 | ||
|
|
7df1431ad2 | ||
|
|
4d4680961e | ||
|
|
1cae99b812 | ||
|
|
3727d19311 | ||
|
|
c45c093f4f | ||
|
|
b613d3e312 | ||
|
|
4cff9247b0 | ||
|
|
b9a26ec28d | ||
|
|
245f81e888 | ||
|
|
204c1ba9f2 | ||
|
|
a7a4be133c | ||
|
|
14f9a46d7a | ||
|
|
003dd040dc | ||
|
|
97cf53217e | ||
|
|
7c1805826d | ||
|
|
d6a2b4dfc4 | ||
|
|
d70952520a | ||
|
|
a57867b806 | ||
|
|
17d7583cfc | ||
|
|
55ad95081b | ||
|
|
da8da1759f | ||
|
|
b4e758b9ee | ||
|
|
3ba41db699 | ||
|
|
cfc47cf483 | ||
|
|
38c8be995b | ||
|
|
492207700b | ||
|
|
b69adefbf8 | ||
|
|
361299f51e | ||
|
|
025091c3f6 | ||
|
|
a54d70036b | ||
|
|
9e67b5962c | ||
|
|
ed0c080163 | ||
|
|
21389d84fc | ||
|
|
0fe54631ad | ||
|
|
36ea5200f2 | ||
|
|
d9934160a6 | ||
|
|
b9c92c48d3 | ||
|
|
6d23df6156 | ||
|
|
a913ab72c2 | ||
|
|
f6d33a2ac1 |
123
.appveyor.yml
@@ -1,126 +1,78 @@
|
||||
image: Visual Studio 2019
|
||||
clone_depth: 400
|
||||
|
||||
environment:
|
||||
global:
|
||||
# SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the
|
||||
# /E:ON and /V:ON options are not enabled in the batch script intepreter
|
||||
# See: http://stackoverflow.com/a/13751649/163740
|
||||
CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\appveyor\\run_with_env.cmd"
|
||||
|
||||
matrix:
|
||||
|
||||
- PYTHON: "C:\\Python36"
|
||||
PYTHON_VERSION: "3.6.x"
|
||||
PYTHON_ARCH: "32"
|
||||
init:
|
||||
- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
- PYTHON: "C:\\Python37-x64"
|
||||
# Should be enabled only for build process debugging
|
||||
# init:
|
||||
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
install:
|
||||
# If there is a newer build queued for the same PR, cancel this one.
|
||||
# The AppVeyor 'rollout builds' option is supposed to serve the same
|
||||
# purpose but it is problematic because it tends to cancel builds pushed
|
||||
# directly to master instead of just PR builds (or the converse).
|
||||
# credits: JuliaLang developers.
|
||||
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
|
||||
https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
|
||||
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
|
||||
throw "There are newer queued builds for this pull request, failing early." }
|
||||
- ps: echo("OS version:")
|
||||
- ps: "[System.Environment]::OSVersion.Version"
|
||||
|
||||
- ECHO "Filesystem root:"
|
||||
- ps: "ls \"C:/\""
|
||||
- ps: echo("Filesystem - root:")
|
||||
- ps: "ls \"C:\\\""
|
||||
|
||||
- ECHO "Filesystem projects root:"
|
||||
- ps: echo("Filesystem - projects root:")
|
||||
- ps: "ls \"C:\\projects\\\""
|
||||
|
||||
- ECHO "Filesystem pyfa root:"
|
||||
- ps: "ls \"C:\\projects\\$env:APPVEYOR_PROJECT_SLUG\""
|
||||
- ps: echo("Filesystem - pyfa root:")
|
||||
- ps: "ls \"C:\\projects\\$env:APPVEYOR_PROJECT_SLUG\\\""
|
||||
|
||||
- ECHO "Installed SDKs:"
|
||||
- ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\""
|
||||
- ps: echo("Filesystem - installed SDKs:")
|
||||
- ps: "ls \"C:\\Program Files (x86)\\Windows Kits\\\""
|
||||
|
||||
# Prepend newly installed Python to the PATH of this build (this cannot be
|
||||
# done from inside the powershell script as it would require to restart
|
||||
# the parent CMD process).
|
||||
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
||||
- cmd: "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
||||
|
||||
- "python --version"
|
||||
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
|
||||
- cmd: "python --version"
|
||||
- cmd: "python -c \"import struct; print(struct.calcsize('P') * 8)\""
|
||||
|
||||
# Upgrade to the latest version of pip to avoid it displaying warnings
|
||||
# about it being out of date.
|
||||
- "pip install --disable-pip-version-check --user --upgrade pip"
|
||||
- cmd: "python -m pip install --upgrade pip"
|
||||
|
||||
# Install the build dependencies of the project. If some dependencies contain
|
||||
# compiled extensions and are not provided as pre-built wheel packages,
|
||||
# pip will build them from source using the MSVC compiler matching the
|
||||
# target Python version and architecture
|
||||
- ECHO "Install pip requirements:"
|
||||
- "python -m pip install -r requirements.txt"
|
||||
- "python -m pip install PyInstaller"
|
||||
- ps: echo("Install pip requirements:")
|
||||
# This one is needed to build wxpython 4.0.6 on windows
|
||||
- cmd: "python -m pip install pathlib2"
|
||||
- cmd: "python -m pip install -r requirements.txt"
|
||||
- cmd: "python -m pip install PyInstaller==3.6"
|
||||
|
||||
before_build:
|
||||
# directory that will contain the built files
|
||||
- ps: $env:PYFA_DIST_DIR = "c:\projects\$env:APPVEYOR_PROJECT_SLUG\dist"
|
||||
- ps: $env:PYFA_VERSION = (python ./scripts/dump_version.py)
|
||||
- ps: echo("pyfa version ")
|
||||
- ps: echo ($env:PYFA_VERSION)
|
||||
- ps: echo("pyfa version $env:PYFA_VERSION")
|
||||
|
||||
build_script:
|
||||
- ECHO "Build pyfa:"
|
||||
|
||||
- ps: echo("Build pyfa:")
|
||||
# Build gamedata DB
|
||||
- "python db_update.py"
|
||||
##########
|
||||
# PyInstaller - create binaries for pyfa
|
||||
##########
|
||||
- cmd: "python db_update.py"
|
||||
# Build command for PyInstaller
|
||||
- "python -m PyInstaller --noupx --clean --windowed --noconsole -y pyfa.spec"
|
||||
- cmd: "python -m PyInstaller --noupx --clean --windowed --noconsole -y pyfa.spec"
|
||||
# Copy over manifest (See pyfa-org/pyfa#1622)
|
||||
- ps: xcopy /y dist_assets\win\pyfa.exe.manifest $env:PYFA_DIST_DIR\pyfa\
|
||||
# Not really sure if this is needed, but why not
|
||||
- ps: xcopy /y dist_assets\win\Microsoft.VC90.CRT.manifest $env:PYFA_DIST_DIR\pyfa\
|
||||
|
||||
##########
|
||||
# InnoScript EXE building
|
||||
# This is in a separate script because I don't feel like copying over the logic to AppVeyor script right now...
|
||||
##########
|
||||
- "python dist_assets/win/dist.py"
|
||||
# InnoScript EXE building. This is in a separate script because I don't feel like copying over the logic to AppVeyor script right now...
|
||||
- cmd: "python dist_assets/win/dist.py"
|
||||
- ps: dir $env:PYFA_DIST_DIR/
|
||||
#- ECHO "Build pyfa (Debug):"
|
||||
#- copy C:\projects\pyfa\dist_assets\win\pyfa_debug.spec C:\projects\pyfa\pyfa_debug.spec
|
||||
#- "pyinstaller.exe --clean --noconfirm --windowed --upx-dir=C:\\projects\\pyfa\\scripts\\upx.exe C:\\projects\\pyfa\\pyfa_debug.spec"
|
||||
|
||||
build: on
|
||||
|
||||
after_build:
|
||||
- ps: "ls \"./\""
|
||||
#- ps: "ls \"C:\\projects\\pyfa\\build\\pyfa\\\""
|
||||
# - ps: "ls \"C:\\projects\\$env:APPVEYOR_PROJECT_SLUG\\build\\exe.win32-2.7\\\""
|
||||
# Zip
|
||||
# APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER
|
||||
#- 7z a build.zip -r C:\projects\pyfa\build\pyfa\*.*
|
||||
- ps: 7z a "pyfa-$env:PYFA_VERSION-win.zip" -r "$env:PYFA_DIST_DIR\pyfa\*.*"
|
||||
#- 7z a pyfa_debug.zip -r C:\projects\pyfa\dist\pyfa_debug\*.*
|
||||
|
||||
on_success:
|
||||
# Do nothing right now
|
||||
- ps: 7z a "pyfa-$env:PYFA_VERSION-win.zip" -r "$env:PYFA_DIST_DIR\pyfa\*"
|
||||
|
||||
test_script:
|
||||
#- tox
|
||||
#- "py.test --cov=./"
|
||||
# Run the project tests
|
||||
# - "%CMD_IN_ENV% python C:/projects/eve-gnosis/setup.py nosetests"
|
||||
|
||||
after_test:
|
||||
# If tests are successful, create binary packages for the project.
|
||||
# - "%CMD_IN_ENV% python setup.py bdist_wheel"
|
||||
# - "%CMD_IN_ENV% python setup.py bdist_wininst"
|
||||
# - "%CMD_IN_ENV% python setup.py bdist_msi"
|
||||
# - ps: "ls dist"
|
||||
# Ha... we're just building
|
||||
|
||||
artifacts:
|
||||
# Archive the generated packages in the ci.appveyor.com build report.
|
||||
- path: pyfa*-win.zip
|
||||
- path: pyfa*-win.exe
|
||||
#- path: pyfa_debug.zip
|
||||
# name: Pyfa_debug
|
||||
|
||||
deploy:
|
||||
tag: $(pyfa_version)
|
||||
@@ -128,10 +80,9 @@ deploy:
|
||||
description: 'Release description'
|
||||
provider: GitHub
|
||||
auth_token:
|
||||
secure: BfNHO66ff5hVx2O2ORbl49X0U/5h2V2T0IuRZDwm7fd1HvsVluF0wRCbl29oRp1M
|
||||
secure: X+U3hOAMTt7HGXCR/LXaGNF6qyhUXetrjz5+xlWiNJQ3XEdzhZZmHK75m0Hm6qre
|
||||
draft: true
|
||||
force_update: false
|
||||
# deploy on tag push only
|
||||
on:
|
||||
APPVEYOR_REPO_TAG: true # deploy on tag push only
|
||||
#on_success:
|
||||
# - TODO: upload the content of dist/*.whl to a public wheelhouse
|
||||
#
|
||||
APPVEYOR_REPO_TAG: true
|
||||
|
||||
@@ -3,13 +3,12 @@ language: python
|
||||
git:
|
||||
depth: 400
|
||||
python:
|
||||
- 3.6
|
||||
- 3.8
|
||||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
osx_image: xcode7.3
|
||||
osx_image: xcode11.3
|
||||
language: generic
|
||||
env: PYTHON=3.6.1
|
||||
before_install:
|
||||
- bash scripts/setup-osx.sh
|
||||
install:
|
||||
@@ -22,7 +21,7 @@ before_deploy:
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: Xfu0xApoB0zUPLXl29aYUulVC3iA4/3bXQwwADKCfAKZwxgNon4dLbO7Rie5/7Ukf2POL0KwmRaQGN3kOr+XSoIVTE4M5sXxnhiaaLGKQ+48hDizLE6JuXcZGJvkxUaghaTzIdCwHsG7VGBsPfQgfGsjJcfBp8tFNLmRyM/Jpsr8T6BR2MxtBIEUVy8zrOWFNZqnmWrY2pWMsB9fYt3JFNdpqeIgRAYqbBsBcZQ1MngLTi3ztuYS5IaF+lk06RrnBlHmUsJu/5nCvIpvPvD0i2BLZ3Uu0+Fn+8QWUgjJEL9MNseXZMXynu05xd8YRk7Ajc9CUrzQIIbAktyteYp85kE3pUJHmrMLcXhh7nqkwttR5/47Zwa3OLJLJFKBxMx6wY5jFkJjkV08850B7aWrmTFl/Eqc3Q5nZMuiEt3wFRbjxHi9h1mTN/fkxfRRHg8u3ENGPR+ZPiFC3J18qtks/B/hsKjjHvZP1i79OYlET4V/zyLyyQkCbpDaARQANuotLYJyZ7tH+KWEyRsvTi0M9Yev9mNNw6aI4vzh4HfkEhvcvnWnYwckPj1dnjQ573Qpw0Z9wsconoWfHAn+hBDt3+YLMrrFZl++mCRskHH1mZChX3aGMDi49zD0kfxBUkYPOAhguc6PwudBxHUZP+O6T/SoHylff6EizCE/k5dGeAk=
|
||||
secure: D8tBW0kyHlKf/sXS69aIuexsYTx9auY2DzudKFlfcvdzqat4N2XZqZbZCTVd7YVvptQ8Dj0oZ/p3KUxEGpnJZmlTeJL142rpM/qaNd6wOIMy2yUde/aZl+W9JLFNQp7KHutM+MxObYLzJGihx/8YsupmFx6lxgdngGDXtXYZe/ruDIWDs92ShoKJ4vlce9Csm7eGKv7wv6Z6V9sD5FS3E9J8xdWStHxsbrkPBOflmG+uHU09dpEqzUm+ZYROIoTwig1Xbw3fw+gfjmNrfdSU4fAJcVZI1hrgoenZyJbMfhI2Ej/nZdbZgaXcZNF/eUpqOGgbPe1JljqFnHTbexcE+LPBVyAToScsGMpByHhig67DrZ0nk9gSZoC6CPNl5YS6xub+5dncMJ3P5L03DOGYRu4SL9NczbeuQyKuea7+JPP/8VLwfFDSEqbNEAmgzABAzrdfano+VXtuBuE/Tiy5eE7le9hJu6aSQoKW1SA3cUhMsmr2amzdO96sh+PN8FA1oNr45Yuy0pqOj4SUIkb8JUy4th7vgdhljEkSxrHDK1UcHpxUTp+IIUZkZVVk50aH68dQZxGwSTVOeRxpjrTcEf7VCGaM98qxi/ZK4RW6Ewiq0eo0AxwEeB2Zm841lycGPR/406vM9/ZBzv5IhELIdDdVWTk+dGjJBXB8z5hPJOg=
|
||||
file_glob: true
|
||||
file: "dist/pyfa-*.zip"
|
||||
skip_cleanup: true
|
||||
|
||||
@@ -49,6 +49,8 @@ def DBInMemory_test():
|
||||
gamedata_version = gamedata_session.execute(
|
||||
"SELECT `field_value` FROM `metadata` WHERE `field_name` LIKE 'client_build'"
|
||||
).fetchone()[0]
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as e:
|
||||
print("Missing gamedata version.")
|
||||
gamedata_version = None
|
||||
|
||||
@@ -233,6 +233,8 @@ def defLogging():
|
||||
# reset=False,
|
||||
)
|
||||
])
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
print("Critical error attempting to setup logging. Falling back to console only.")
|
||||
logging_setup = NestedSetup([
|
||||
|
||||
42
db_update.py
@@ -23,6 +23,7 @@ import functools
|
||||
import itertools
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sqlite3
|
||||
import sys
|
||||
|
||||
@@ -32,7 +33,7 @@ DB_PATH = os.path.join(ROOT_DIR, 'eve.db')
|
||||
JSON_DIR = os.path.join(ROOT_DIR, 'staticdata')
|
||||
if ROOT_DIR not in sys.path:
|
||||
sys.path.insert(0, ROOT_DIR)
|
||||
GAMEDATA_SCHEMA_VERSION = 2
|
||||
GAMEDATA_SCHEMA_VERSION = 3
|
||||
|
||||
|
||||
def db_needs_update():
|
||||
@@ -40,7 +41,7 @@ def db_needs_update():
|
||||
try:
|
||||
with open(os.path.join(JSON_DIR, 'phobos', 'metadata.json')) as f:
|
||||
data_version = next((r['field_value'] for r in json.load(f) if r['field_name'] == 'client_build'))
|
||||
except KeyboardInterrupt:
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
# If we have no source data - return None; should not update in this case
|
||||
except:
|
||||
@@ -61,7 +62,7 @@ def db_needs_update():
|
||||
db_schema_version = int(row[0])
|
||||
cursor.close()
|
||||
db.close()
|
||||
except KeyboardInterrupt:
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
print('Error when fetching gamedata DB metadata')
|
||||
@@ -206,7 +207,7 @@ def update_db():
|
||||
def processDogmaEffects():
|
||||
print('processing dogmaeffects')
|
||||
data = _readData('fsd_binary', 'dogmaeffects', keyIdName='effectID')
|
||||
_addRows(data, eos.gamedata.Effect)
|
||||
_addRows(data, eos.gamedata.Effect, fieldMap={'resistanceAttributeID': 'resistanceID'})
|
||||
|
||||
def processDogmaTypeEffects(eveTypesData):
|
||||
print('processing dogmatypeeffects')
|
||||
@@ -458,6 +459,38 @@ def update_db():
|
||||
if itemReplacements is not None:
|
||||
item.replacements = ','.join('{}'.format(tid) for tid in sorted(itemReplacements))
|
||||
|
||||
def processImplantSets(eveTypesData):
|
||||
print('composing implant sets')
|
||||
# Includes only implants which can be considered part of sets, not all implants
|
||||
implant_groups = (300, 1730)
|
||||
specials = {'Genolution': ('Genolution Core Augmentation', r'CA-\d+')}
|
||||
implantSets = {}
|
||||
for row in eveTypesData:
|
||||
if not row.get('published'):
|
||||
continue
|
||||
if row.get('groupID') not in implant_groups:
|
||||
continue
|
||||
typeName = row.get('typeName', '')
|
||||
# Regular sets matching
|
||||
m = re.match('(?P<grade>(High|Mid|Low)-grade) (?P<set>\w+) (?P<implant>(Alpha|Beta|Gamma|Delta|Epsilon|Omega))', typeName)
|
||||
if m:
|
||||
implantSets.setdefault((m.group('grade'), m.group('set')), set()).add(row['typeID'])
|
||||
# Special set matching
|
||||
for setHandle, (setName, implantPattern) in specials.items():
|
||||
pattern = '(?P<set>{}) (?P<implant>{})'.format(setName, implantPattern)
|
||||
m = re.match(pattern, typeName)
|
||||
if m:
|
||||
implantSets.setdefault((None, setHandle), set()).add(row['typeID'])
|
||||
break
|
||||
data = []
|
||||
for (gradeName, setName), implants in implantSets.items():
|
||||
if len(implants) < 2:
|
||||
continue
|
||||
implants = ','.join('{}'.format(tid) for tid in sorted(implants))
|
||||
row = {'setName': setName, 'gradeName': gradeName, 'implants': implants}
|
||||
data.append(row)
|
||||
_addRows(data, eos.gamedata.ImplantSet)
|
||||
|
||||
eveTypesData = processEveTypes()
|
||||
eveGroupsData = processEveGroups()
|
||||
processEveCategories()
|
||||
@@ -476,6 +509,7 @@ def update_db():
|
||||
eos.db.gamedata_session.flush()
|
||||
processReqSkills(eveTypesData)
|
||||
processReplacements(eveTypesData, eveGroupsData, dogmaTypeAttributesData, dogmaTypeEffectsData)
|
||||
processImplantSets(eveTypesData)
|
||||
|
||||
# Add schema version to prevent further updates
|
||||
metadata_schema_version = eos.gamedata.MetaData()
|
||||
|
||||
@@ -30,7 +30,8 @@ added_files = [
|
||||
|
||||
import_these = [
|
||||
'numpy.core._dtype_ctypes', # https://github.com/pyinstaller/pyinstaller/issues/3982
|
||||
'sqlalchemy.ext.baked' # windows build doesn't launch without if when using sqlalchemy 1.3.x
|
||||
'sqlalchemy.ext.baked', # windows build doesn't launch without if when using sqlalchemy 1.3.x
|
||||
'pkg_resources.py2_warn' # issue 2156
|
||||
]
|
||||
|
||||
icon = os.path.join(os.getcwd(), "dist_assets", "mac", "pyfa.icns")
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
# This apes hook-matplotlib.backends.py, but REMOVES backends, all but
|
||||
# the ones in the list below.
|
||||
# Courtesy of https://github.com/bpteague/cytoflow/blob/70f9291/packaging/hook-matplotlib.backends.py
|
||||
|
||||
KEEP = ["WXAgg", "WX", "agg"]
|
||||
|
||||
from PyInstaller.compat import is_darwin
|
||||
from PyInstaller.utils.hooks import (
|
||||
eval_statement, exec_statement, logger)
|
||||
|
||||
|
||||
def get_matplotlib_backend_module_names():
|
||||
"""
|
||||
List the names of all matplotlib backend modules importable under the
|
||||
current Python installation.
|
||||
Returns
|
||||
----------
|
||||
list
|
||||
List of the fully-qualified names of all such modules.
|
||||
"""
|
||||
# Statement safely importing a single backend module.
|
||||
import_statement = """
|
||||
import os, sys
|
||||
# Preserve stdout.
|
||||
sys_stdout = sys.stdout
|
||||
try:
|
||||
# Redirect output printed by this importation to "/dev/null", preventing
|
||||
# such output from being erroneously interpreted as an error.
|
||||
with open(os.devnull, 'w') as dev_null:
|
||||
sys.stdout = dev_null
|
||||
__import__('%s')
|
||||
# If this is an ImportError, print this exception's message without a traceback.
|
||||
# ImportError messages are human-readable and require no additional context.
|
||||
except ImportError as exc:
|
||||
sys.stdout = sys_stdout
|
||||
print(exc)
|
||||
# Else, print this exception preceded by a traceback. traceback.print_exc()
|
||||
# prints to stderr rather than stdout and must not be called here!
|
||||
except Exception:
|
||||
sys.stdout = sys_stdout
|
||||
import traceback
|
||||
print(traceback.format_exc())
|
||||
"""
|
||||
|
||||
# List of the human-readable names of all available backends.
|
||||
backend_names = eval_statement(
|
||||
'import matplotlib; print(matplotlib.rcsetup.all_backends)')
|
||||
|
||||
# List of the fully-qualified names of all importable backend modules.
|
||||
module_names = []
|
||||
|
||||
# If the current system is not OS X and the "CocoaAgg" backend is available,
|
||||
# remove this backend from consideration. Attempting to import this backend
|
||||
# on non-OS X systems halts the current subprocess without printing output
|
||||
# or raising exceptions, preventing its reliable detection.
|
||||
if not is_darwin and 'CocoaAgg' in backend_names:
|
||||
backend_names.remove('CocoaAgg')
|
||||
|
||||
# For safety, attempt to import each backend in a unique subprocess.
|
||||
for backend_name in backend_names:
|
||||
if backend_name in KEEP:
|
||||
continue
|
||||
|
||||
module_name = 'matplotlib.backends.backend_%s' % backend_name.lower()
|
||||
stdout = exec_statement(import_statement % module_name)
|
||||
|
||||
# If no output was printed, this backend is importable.
|
||||
if not stdout:
|
||||
module_names.append(module_name)
|
||||
logger.info(' Matplotlib backend "%s": removed' % backend_name)
|
||||
|
||||
return module_names
|
||||
|
||||
# Freeze all importable backends, as PyInstaller is unable to determine exactly
|
||||
# which backends are required by the current program.
|
||||
e=get_matplotlib_backend_module_names()
|
||||
print(e)
|
||||
excludedimports = e
|
||||
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<noInheritable/>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.VC90.CRT"
|
||||
version="9.0.21022.8"
|
||||
processorArchitecture="x86"
|
||||
publicKeyToken="1fc8b3b9a1e18e3b"/>
|
||||
<file name="MSVCR90.DLL"/>
|
||||
<file name="MSVCM90.DLL"/>
|
||||
<file name="MSVCP90.DLL"/>
|
||||
</assembly>
|
||||
@@ -14,7 +14,7 @@ with open("version.yml", 'r') as file:
|
||||
os.environ["PYFA_DIST_DIR"] = os.path.join(os.getcwd(), 'dist')
|
||||
|
||||
os.environ["PYFA_VERSION"] = version
|
||||
iscc = "C:\Program Files (x86)\Inno Setup 5\ISCC.exe" # inno script location via wine
|
||||
iscc = "C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
|
||||
|
||||
source = os.path.join(os.environ["PYFA_DIST_DIR"], "pyfa")
|
||||
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
#define MyAppURL "https://github.com/pyfa-org/Pyfa/"
|
||||
#define MyAppExeName "pyfa.exe"
|
||||
|
||||
; What version starts with the new structure (1.x.0). This is used to determine if we run directory structure cleanup
|
||||
#define MajorVersionFlag 2
|
||||
#define MinorVersionFlag 0
|
||||
|
||||
#ifndef MyOutputFile
|
||||
#define MyOutputFile LowerCase(StringChange(MyAppName+'-'+MyAppVersion+'-win', " ", "-"))
|
||||
#endif
|
||||
@@ -30,7 +26,6 @@
|
||||
#endif
|
||||
|
||||
[Setup]
|
||||
|
||||
; NOTE: The value of AppId uniquely identifies this application.
|
||||
; Do not use the same AppId value in installers for other applications.
|
||||
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
||||
@@ -41,6 +36,9 @@ AppPublisher={#MyAppPublisher}
|
||||
AppPublisherURL={#MyAppURL}
|
||||
AppSupportURL={#MyAppURL}
|
||||
AppUpdatesURL={#MyAppURL}
|
||||
ArchitecturesAllowed=x64
|
||||
ArchitecturesInstallIn64BitMode=x64
|
||||
CloseApplications=yes
|
||||
DefaultDirName={pf}\{#MyAppName}
|
||||
DefaultGroupName={#MyAppName}
|
||||
AllowNoIcons=yes
|
||||
@@ -49,7 +47,6 @@ OutputDir={#MyOutputDir}
|
||||
OutputBaseFilename={#MyOutputFile}
|
||||
SetupIconFile={#MyAppDir}\pyfa.ico
|
||||
SolidCompression=yes
|
||||
CloseApplications=yes
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
@@ -83,6 +80,7 @@ Type: files; Name: "{app}\*.pyc"
|
||||
|
||||
[Code]
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
function IsAppRunning(const FileName : string): Boolean;
|
||||
var
|
||||
FSWbemLocator: Variant;
|
||||
@@ -99,6 +97,7 @@ begin
|
||||
FSWbemLocator := Unassigned;
|
||||
end;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
procedure RemoveFromVirtualStore;
|
||||
var
|
||||
VirtualStore,FileName,FilePath:String;
|
||||
@@ -115,6 +114,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
function PrepareToInstall(var NeedsRestart: Boolean): String;
|
||||
begin
|
||||
if(IsAppRunning( 'pyfa.exe' )) then
|
||||
@@ -127,54 +127,61 @@ begin
|
||||
end
|
||||
end;
|
||||
|
||||
function GetUninstallString: string;
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
function GetUninstallString(): String;
|
||||
var
|
||||
sUnInstPath: string;
|
||||
sUnInstPath: String;
|
||||
sUnInstallString: String;
|
||||
begin
|
||||
Result := '';
|
||||
sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{{3DA39096-C08D-49CD-90E0-1D177F32C8AA}_is1'); //Your App GUID/ID
|
||||
sUnInstallString := '';
|
||||
if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
|
||||
RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
|
||||
if not RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString) then
|
||||
if not RegQueryStringValue(HKLM32, sUnInstPath, 'UninstallString', sUnInstallString) then
|
||||
RegQueryStringValue(HKCU32, sUnInstPath, 'UninstallString', sUnInstallString);
|
||||
Result := sUnInstallString;
|
||||
end;
|
||||
|
||||
function IsUpgrade: Boolean;
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
function UnInstallOldVersion(): Integer;
|
||||
var
|
||||
sUnInstallString: String;
|
||||
iResultCode: Integer;
|
||||
begin
|
||||
// Return Values:
|
||||
// 1 - uninstall string is empty
|
||||
// 2 - error executing the UnInstallString
|
||||
// 3 - successfully executed the UnInstallString
|
||||
|
||||
// default return value
|
||||
Result := 0;
|
||||
|
||||
// get the uninstall string of the old app
|
||||
sUnInstallString := GetUninstallString();
|
||||
if sUnInstallString <> '' then begin
|
||||
sUnInstallString := RemoveQuotes(sUnInstallString);
|
||||
if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
|
||||
Result := 3
|
||||
else
|
||||
Result := 2;
|
||||
end else
|
||||
Result := 1;
|
||||
end;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
function IsUpgrade(): Boolean;
|
||||
begin
|
||||
Result := (GetUninstallString() <> '');
|
||||
end;
|
||||
|
||||
function InitializeSetup: Boolean;
|
||||
var
|
||||
V: Integer;
|
||||
iResultCode: Integer;
|
||||
sUnInstallString: string;
|
||||
iOldVersionMajor: Cardinal;
|
||||
iOldVersionMinor: Cardinal;
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
procedure CurStepChanged(CurStep: TSetupStep);
|
||||
begin
|
||||
Result := True; // in case when no previous version is found
|
||||
if RegValueExists(HKEY_LOCAL_MACHINE,'Software\Microsoft\Windows\CurrentVersion\Uninstall\{3DA39096-C08D-49CD-90E0-1D177F32C8AA}_is1', 'UninstallString') then //Your App GUID/ID
|
||||
if (CurStep=ssInstall) then
|
||||
begin
|
||||
RegQueryDWordValue(HKEY_LOCAL_MACHINE,
|
||||
'Software\Microsoft\Windows\CurrentVersion\Uninstall\{3DA39096-C08D-49CD-90E0-1D177F32C8AA}_is1',
|
||||
'MajorVersion', iOldVersionMajor);
|
||||
RegQueryDWordValue(HKEY_LOCAL_MACHINE,
|
||||
'Software\Microsoft\Windows\CurrentVersion\Uninstall\{3DA39096-C08D-49CD-90E0-1D177F32C8AA}_is1',
|
||||
'MinorVersion', iOldVersionMinor);
|
||||
if (iOldVersionMajor < {#MajorVersionFlag}) or ((iOldVersionMajor = {#MajorVersionFlag}) and (iOldVersionMinor < {#MinorVersionFlag})) then // If old version with old structure is installed.
|
||||
if (IsUpgrade()) then
|
||||
begin
|
||||
V := MsgBox(ExpandConstant('An old version of pyfa was detected. Due to recent changes in the application structure, you must uninstall the previous version first. This will not affect your user data (saved fittings, characters, etc.). Do you want to uninstall now?'), mbInformation, MB_YESNO); //Custom Message if App installed
|
||||
if V = IDYES then
|
||||
begin
|
||||
sUnInstallString := GetUninstallString();
|
||||
sUnInstallString := RemoveQuotes(sUnInstallString);
|
||||
Exec(ExpandConstant(sUnInstallString), '', '', SW_SHOW, ewWaitUntilTerminated, iResultCode);
|
||||
Result := True; //if you want to proceed after uninstall
|
||||
//Exit; //if you want to quit after uninstall
|
||||
end
|
||||
else
|
||||
Result := False; //when older version present and not uninstalled
|
||||
UnInstallOldVersion();
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||
|
||||
@@ -20,7 +20,6 @@ added_files = [
|
||||
('../../service/jargon/*.yaml', 'service/jargon'),
|
||||
('../../dist_assets/win/pyfa.ico', '.'),
|
||||
('../../dist_assets/win/pyfa.exe.manifest', '.'),
|
||||
('../../dist_assets/win/Microsoft.VC90.CRT.manifest', '.'),
|
||||
(requests.certs.where(), '.'), # is this needed anymore?
|
||||
('../../eve.db', '.'),
|
||||
('../../README.md', '.'),
|
||||
@@ -30,7 +29,8 @@ added_files = [
|
||||
|
||||
import_these = [
|
||||
'numpy.core._dtype_ctypes', # https://github.com/pyinstaller/pyinstaller/issues/3982
|
||||
'sqlalchemy.ext.baked' # windows build doesn't launch without if when using sqlalchemy 1.3.x
|
||||
'sqlalchemy.ext.baked', # windows build doesn't launch without if when using sqlalchemy 1.3.x
|
||||
'pkg_resources.py2_warn' # issue 2156
|
||||
]
|
||||
|
||||
# Walk directories that do dynamic importing
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
# -*- mode: python -*-
|
||||
|
||||
# Note: This script is provided AS-IS for those that may be interested.
|
||||
# pyfa does not currently support pyInstaller (or any other build process) 100% at the moment
|
||||
|
||||
# Command line to build:
|
||||
# (Run from directory where pyfa.py and pyfa.spec lives.)
|
||||
# c:\Python27\scripts\pyinstaller.exe --clean --noconfirm --windowed --upx-dir=.\scripts\upx.exe pyfa.spec
|
||||
|
||||
# Don't forget to change the path to where your pyfa.py and pyfa.spec lives
|
||||
# pathex=['C:\\Users\\Ebag333\\Documents\\GitHub\\Ebag333\\Pyfa'],
|
||||
|
||||
import os
|
||||
|
||||
block_cipher = None
|
||||
|
||||
added_files = [
|
||||
( 'imgs/gui/*.png', 'imgs/gui' ),
|
||||
( 'imgs/gui/*.gif', 'imgs/gui' ),
|
||||
( 'imgs/icons/*.png', 'imgs/icons' ),
|
||||
( 'imgs/renders/*.png', 'imgs/renders' ),
|
||||
( 'dist_assets/win/pyfa.ico', '.' ),
|
||||
( 'dist_assets/cacert.pem', '.' ),
|
||||
( 'eve.db', '.' ),
|
||||
( 'README.md', '.' ),
|
||||
( 'LICENSE', '.' ),
|
||||
]
|
||||
|
||||
import_these = []
|
||||
|
||||
# Walk eos.effects and add all effects so we can import them properly
|
||||
for root, folders, files in os.walk("eos/effects"):
|
||||
for file_ in files:
|
||||
if file_.endswith(".py") and not file_.startswith("_"):
|
||||
mod_name = "{}.{}".format(
|
||||
root.replace("/", "."),
|
||||
file_.split(".py")[0],
|
||||
)
|
||||
import_these.append(mod_name)
|
||||
|
||||
a = Analysis(
|
||||
['pyfa.py'],
|
||||
pathex=['C:\\projects\\pyfa\\'],
|
||||
binaries=[],
|
||||
datas=added_files,
|
||||
hiddenimports=import_these,
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
)
|
||||
|
||||
pyz = PYZ(
|
||||
a.pure,
|
||||
a.zipped_data,
|
||||
cipher=block_cipher,
|
||||
)
|
||||
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
exclude_binaries=True,
|
||||
debug=True,
|
||||
console=True,
|
||||
strip=False,
|
||||
upx=True,
|
||||
name='pyfa_debug',
|
||||
icon='dist_assets/win/pyfa.ico',
|
||||
onefile=False,
|
||||
)
|
||||
|
||||
coll = COLLECT(
|
||||
exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
onefile=False,
|
||||
name='pyfa_debug',
|
||||
icon='dist_assets/win/pyfa.ico',
|
||||
)
|
||||
@@ -56,6 +56,8 @@ try:
|
||||
config.gamedata_date = gamedata_session.execute(
|
||||
"SELECT `field_value` FROM `metadata` WHERE `field_name` LIKE 'dump_time'"
|
||||
).fetchone()[0]
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as e:
|
||||
pyfalog.warning("Missing gamedata version.")
|
||||
pyfalog.critical(e)
|
||||
@@ -82,7 +84,7 @@ sd_lock = threading.RLock()
|
||||
pyfalog.debug('Importing gamedata DB scheme')
|
||||
# Import all the definitions for all our database stuff
|
||||
# noinspection PyPep8
|
||||
from eos.db.gamedata import alphaClones, attribute, category, effect, group, item, marketGroup, metaData, metaGroup, queries, traits, unit, dynamicAttributes
|
||||
from eos.db.gamedata import alphaClones, attribute, category, effect, group, item, marketGroup, metaData, metaGroup, queries, traits, unit, dynamicAttributes, implantSet
|
||||
pyfalog.debug('Importing saveddata DB scheme')
|
||||
# noinspection PyPep8
|
||||
from eos.db.saveddata import booster, cargo, character, damagePattern, databaseRepair, drone, fighter, fit, implant, implantSet, \
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
__all__ = ["attribute", "category", "effect", "group", "metaData", "dynamicAttributes",
|
||||
"item", "marketGroup", "metaGroup", "unit", "alphaClones"]
|
||||
"item", "marketGroup", "metaGroup", "unit", "alphaClones", "implantSet"]
|
||||
|
||||
33
eos/db/gamedata/implantSet.py
Normal file
@@ -0,0 +1,33 @@
|
||||
# ===============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# This file is part of eos.
|
||||
#
|
||||
# eos is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# eos is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
from sqlalchemy import Column, String, Integer, Table
|
||||
from sqlalchemy.orm import mapper, synonym
|
||||
|
||||
from eos.db import gamedata_meta
|
||||
from eos.gamedata import ImplantSet
|
||||
|
||||
implant_set_table = Table("implantsets", gamedata_meta,
|
||||
Column("setID", Integer, primary_key=True),
|
||||
Column("setName", String),
|
||||
Column("gradeName", String),
|
||||
Column("implants", String))
|
||||
|
||||
mapper(ImplantSet, implant_set_table,
|
||||
properties={"ID": synonym("setID")})
|
||||
@@ -26,7 +26,7 @@ from eos.db import gamedata_session
|
||||
from eos.db.gamedata.item import items_table
|
||||
from eos.db.gamedata.group import groups_table
|
||||
from eos.db.util import processEager, processWhere
|
||||
from eos.gamedata import AlphaClone, Attribute, AttributeInfo, Category, DynamicItem, Group, Item, MarketGroup, MetaData, MetaGroup
|
||||
from eos.gamedata import AlphaClone, Attribute, AttributeInfo, Category, DynamicItem, Group, Item, MarketGroup, MetaData, MetaGroup, ImplantSet
|
||||
|
||||
cache = {}
|
||||
configVal = getattr(eos.config, "gamedataCache", None)
|
||||
@@ -424,3 +424,9 @@ def getDynamicItem(itemID, eager=None):
|
||||
except exc.NoResultFound:
|
||||
result = None
|
||||
return result
|
||||
|
||||
|
||||
@cachedQuery(1, "lookfor")
|
||||
def getAllImplantSets():
|
||||
implantSets = gamedata_session.query(ImplantSet).all()
|
||||
return implantSets
|
||||
|
||||
@@ -8,43 +8,25 @@ many upgrade files as there are database versions (version 5 would include
|
||||
upgrade files 1-5)
|
||||
"""
|
||||
|
||||
import pkgutil
|
||||
import re
|
||||
|
||||
from eos.utils.pyinst_support import iterNamespace
|
||||
|
||||
updates = {}
|
||||
appVersion = 0
|
||||
|
||||
prefix = __name__ + "."
|
||||
|
||||
# load modules to work based with and without pyinstaller
|
||||
# from: https://github.com/webcomics/dosage/blob/master/dosagelib/loader.py
|
||||
# see: https://github.com/pyinstaller/pyinstaller/issues/1905
|
||||
|
||||
# load modules using iter_modules()
|
||||
# (should find all filters in normal build, but not pyinstaller)
|
||||
module_names = [m[1] for m in pkgutil.iter_modules(__path__, prefix)]
|
||||
|
||||
# special handling for PyInstaller
|
||||
importers = map(pkgutil.get_importer, __path__)
|
||||
toc = set()
|
||||
for i in importers:
|
||||
if hasattr(i, 'toc'):
|
||||
toc |= i.toc
|
||||
|
||||
for elm in toc:
|
||||
if elm.startswith(prefix):
|
||||
module_names.append(elm)
|
||||
|
||||
for modname in module_names:
|
||||
for modName in iterNamespace(__name__, __path__):
|
||||
# loop through python files, extracting update number and function, and
|
||||
# adding it to a list
|
||||
modname_tail = modname.rsplit('.', 1)[-1]
|
||||
module = __import__(modname, fromlist=True)
|
||||
modname_tail = modName.rsplit('.', 1)[-1]
|
||||
m = re.match("^upgrade(?P<index>\d+)$", modname_tail)
|
||||
if not m:
|
||||
continue
|
||||
index = int(m.group("index"))
|
||||
appVersion = max(appVersion, index)
|
||||
module = __import__(modName, fromlist=True)
|
||||
upgrade = getattr(module, "upgrade", False)
|
||||
if upgrade:
|
||||
updates[index] = upgrade
|
||||
|
||||
@@ -33,9 +33,13 @@ def upgrade(saveddata_engine):
|
||||
try:
|
||||
saveddata_session.execute(commandFits_table.insert(),
|
||||
{"boosterID": value, "boostedID": boosted, "active": 1})
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception:
|
||||
pass
|
||||
saveddata_session.commit()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
# Shouldn't fail unless you have updated database without the old fleet schema and manually modify the database version
|
||||
# If it does, simply fail. Fleet data migration isn't critically important here
|
||||
|
||||
@@ -4235,6 +4235,8 @@ def upgrade(saveddata_engine):
|
||||
|
||||
# And last but not least, delete the last subsystem
|
||||
saveddata_engine.execute("DELETE FROM modules WHERE ID = ?", (oldModules[4][0],))
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
# if something fails, fuck it, we tried. It'll default to the generic conversion below
|
||||
continue
|
||||
|
||||
@@ -6,16 +6,16 @@ Allow use of floats in damage pattern values
|
||||
|
||||
tmpTable = """
|
||||
CREATE TABLE "damagePatternsTemp" (
|
||||
"ID" INTEGER NOT NULL,
|
||||
"name" VARCHAR,
|
||||
"emAmount" FLOAT,
|
||||
"thermalAmount" FLOAT,
|
||||
"kineticAmount" FLOAT,
|
||||
"explosiveAmount" FLOAT,
|
||||
"ownerID" INTEGER,
|
||||
"created" DATETIME,
|
||||
"modified" DATETIME,
|
||||
PRIMARY KEY ("ID"),
|
||||
"ID" INTEGER NOT NULL,
|
||||
"name" VARCHAR,
|
||||
"emAmount" FLOAT,
|
||||
"thermalAmount" FLOAT,
|
||||
"kineticAmount" FLOAT,
|
||||
"explosiveAmount" FLOAT,
|
||||
"ownerID" INTEGER,
|
||||
"created" DATETIME,
|
||||
"modified" DATETIME,
|
||||
PRIMARY KEY ("ID"),
|
||||
FOREIGN KEY("ownerID") REFERENCES users ("ID")
|
||||
)
|
||||
"""
|
||||
|
||||
84
eos/db/migrations/upgrade36.py
Normal file
@@ -0,0 +1,84 @@
|
||||
"""
|
||||
Migration 36
|
||||
|
||||
- Shield Booster, Armor Repairer and Capacitor Transfer tiericide
|
||||
"""
|
||||
|
||||
CONVERSIONS = {
|
||||
6441: ( # Small Clarity Ward Enduring Shield Booster
|
||||
6443, # Small Converse Deflection Catalyzer
|
||||
),
|
||||
6437: ( # Small C5-L Compact Shield Booster
|
||||
6439, # Small Neutron Saturation Injector I
|
||||
),
|
||||
10868: ( # Medium Clarity Ward Enduring Shield Booster
|
||||
10870, # Medium Converse Deflection Catalyzer
|
||||
),
|
||||
10872: ( # Medium C5-L Compact Shield Booster
|
||||
10866, # Medium Neutron Saturation Injector I
|
||||
),
|
||||
10876: ( # Large Clarity Ward Enduring Shield Booster
|
||||
10878, # Large Converse Deflection Catalyzer
|
||||
),
|
||||
10880: ( # Large C5-L Compact Shield Booster
|
||||
10874, # Large Neutron Saturation Injector I
|
||||
),
|
||||
10884: ( # X-Large Clarity Ward Enduring Shield Booster
|
||||
10886, # X-Large Converse Deflection Catalyzer
|
||||
),
|
||||
10888: ( # X-Large C5-L Compact Shield Booster
|
||||
10882, # X-Large Neutron Saturation Injector I
|
||||
),
|
||||
4533: ( # Small ACM Compact Armor Repairer
|
||||
4531, # Small Inefficient Armor Repair Unit
|
||||
),
|
||||
4529: ( # Small I-a Enduring Armor Repairer
|
||||
4535, # Small Automated Carapace Restoration
|
||||
),
|
||||
4573: ( # Medium ACM Compact Armor Repairer
|
||||
4571, # Medium Inefficient Armor Repair Unit
|
||||
),
|
||||
4569: ( # Medium I-a Enduring Armor Repairer
|
||||
4575, # Medium Automated Carapace Restoration
|
||||
),
|
||||
22889: ( # 'Meditation' Medium Armor Repairer I
|
||||
4579, # Medium Nano Armor Repair Unit I
|
||||
),
|
||||
4613: ( # Large ACM Compact Armor Repairer
|
||||
4611, # Large Inefficient Armor Repair Unit
|
||||
),
|
||||
4609: ( # Large I-a Enduring Armor Repairer
|
||||
4615, # Large Automated Carapace Restoration
|
||||
),
|
||||
22891: ( # 'Protest' Large Armor Repairer I
|
||||
4621, # Large 'Reprieve' Vestment Reconstructer I
|
||||
),
|
||||
5093: ( # Small Radiative Scoped Remote Capacitor Transmitter
|
||||
5087, # Small Partial E95a Remote Capacitor Transmitter
|
||||
),
|
||||
5091: ( # Small Inductive Compact Remote Capacitor Transmitter
|
||||
5089, # Small Murky Remote Capacitor Transmitter
|
||||
),
|
||||
16489: ( # Medium Radiative Scoped Remote Capacitor Transmitter
|
||||
16493, # Medium Partial E95b Remote Capacitor Transmitter
|
||||
),
|
||||
16495: ( # Medium Inductive Compact Remote Capacitor Transmitter
|
||||
16491, # Medium Murky Remote Capacitor Transmitter
|
||||
),
|
||||
16481: ( # Large Radiative Scoped Remote Capacitor Transmitter
|
||||
16485, # Large Partial E95c Remote Capacitor Transmitter
|
||||
),
|
||||
16487: ( # Large Inductive Compact Remote Capacitor Transmitter
|
||||
16483, # Large Murky Remote Capacitor Transmitter
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Convert modules
|
||||
for replacement_item, list in CONVERSIONS.items():
|
||||
for retired_item in list:
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
44
eos/db/migrations/upgrade37.py
Normal file
@@ -0,0 +1,44 @@
|
||||
"""
|
||||
Migration 37
|
||||
|
||||
- Capacitor Booster tiericide
|
||||
"""
|
||||
|
||||
CONVERSIONS = {
|
||||
4959: ( # 'Seed' Micro Capacitor Booster I
|
||||
4957, # Micro Brief Capacitor Overcharge I
|
||||
4961, # Micro Tapered Capacitor Infusion I
|
||||
4955, # Micro F-RX Prototype Capacitor Boost
|
||||
3556, # Micro Capacitor Booster I
|
||||
3558, # Micro Capacitor Booster II
|
||||
15774, # Ammatar Navy Micro Capacitor Booster
|
||||
14180, # Dark Blood Micro Capacitor Booster
|
||||
14182, # True Sansha Micro Capacitor Booster
|
||||
15782, # Imperial Navy Micro Capacitor Booster
|
||||
),
|
||||
5011: ( # Small F-RX Compact Capacitor Booster
|
||||
5009, # Small Brief Capacitor Overcharge I
|
||||
5013, # Small Tapered Capacitor Infusion I
|
||||
5007, # Small F-RX Prototype Capacitor Boost
|
||||
),
|
||||
4833: ( # Medium F-RX Compact Capacitor Booster
|
||||
4831, # Medium Brief Capacitor Overcharge I
|
||||
4835, # Medium Tapered Capacitor Infusion I
|
||||
4829, # Medium F-RX Prototype Capacitor Boost
|
||||
),
|
||||
5051: ( # Heavy F-RX Compact Capacitor Booster
|
||||
5049, # Heavy Brief Capacitor Overcharge I
|
||||
5053, # Heavy Tapered Capacitor Infusion I
|
||||
5047, # Heavy F-RX Prototype Capacitor Boost
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
# Convert modules
|
||||
for replacement_item, list in CONVERSIONS.items():
|
||||
for retired_item in list:
|
||||
saveddata_engine.execute('UPDATE "modules" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
saveddata_engine.execute('UPDATE "cargo" SET "itemID" = ? WHERE "itemID" = ?',
|
||||
(replacement_item, retired_item))
|
||||
@@ -560,6 +560,8 @@ def commit():
|
||||
with sd_lock:
|
||||
try:
|
||||
saveddata_session.commit()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception:
|
||||
saveddata_session.rollback()
|
||||
exc_info = sys.exc_info()
|
||||
@@ -570,6 +572,8 @@ def flush():
|
||||
with sd_lock:
|
||||
try:
|
||||
saveddata_session.flush()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception:
|
||||
saveddata_session.rollback()
|
||||
exc_info = sys.exc_info()
|
||||
|
||||
571
eos/effects.py
@@ -184,6 +184,8 @@ class Effect(EqBase):
|
||||
self.__activeByDefault = True
|
||||
self.__type = None
|
||||
pyfalog.error("AttributeError generating handler: {0}", e)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as e:
|
||||
self.__handler = eos.effects.DummyEffect.handler
|
||||
self.__runTime = "normal"
|
||||
@@ -200,6 +202,8 @@ class Effect(EqBase):
|
||||
|
||||
try:
|
||||
return self.__effectDef.get(key, None)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
return getattr(self.__effectDef, key, None)
|
||||
|
||||
@@ -719,5 +723,15 @@ class Unit(EqBase):
|
||||
|
||||
return value
|
||||
|
||||
|
||||
class Traits(EqBase):
|
||||
pass
|
||||
|
||||
|
||||
class ImplantSet(EqBase):
|
||||
|
||||
@property
|
||||
def fullName(self):
|
||||
if not self.gradeName:
|
||||
return self.setName
|
||||
return '{} {}'.format(self.gradeName, self.setName)
|
||||
|
||||
@@ -118,15 +118,15 @@ BUILTINS = OrderedDict([
|
||||
# Source: ticket #2067
|
||||
(-86, ('[NPC][Invasion][Invading Precursor Entities]Dread', 0, 417, 0, 583)),
|
||||
(-87, ('[NPC][Invasion][Invading Precursor Entities]Normal Subcaps', 0, 610, 0, 390)),
|
||||
(-88, ('[NPC][Invasion][Invading Precursor Entities]Subcaps w/missiles 0% spool up', 363, 160, 363, 115)),
|
||||
(-89, ('[NPC][Invasion][Invading Precursor Entities]Subcaps w/missiles 50% spool up', 286, 249, 286, 179)),
|
||||
(-90, ('[NPC][Invasion][Invading Precursor Entities]Subcaps w/missiles 100% spool up', 236, 307, 236, 221)),
|
||||
(-88, ('[NPC][Invasion][Invading Precursor Entities]Subcaps w/missiles 0% spool up', 367, 155, 367, 112)),
|
||||
(-89, ('[NPC][Invasion][Invading Precursor Entities]Subcaps w/missiles 50% spool up', 291, 243, 291, 175)),
|
||||
(-90, ('[NPC][Invasion][Invading Precursor Entities]Subcaps w/missiles 100% spool up', 241, 301, 241, 217)),
|
||||
(-91, ('[NPC][Invasion][Retaliating Amarr Entities]Dread/Subcaps', 583, 417, 0, 0)),
|
||||
(-92, ('[NPC][Invasion][Retaliating Caldari Entities]Dread', 1000, 0, 0, 0)),
|
||||
(-93, ('[NPC][Invasion][Retaliating Caldari Entities]Subcaps', 511, 21, 29, 439)),
|
||||
(-93, ('[NPC][Invasion][Retaliating Caldari Entities]Subcaps', 511, 21, 29, 440)),
|
||||
(-94, ('[NPC][Invasion][Retaliating Gallente Entities]Dread/Subcaps', 0, 417, 583, 0)),
|
||||
(-95, ('[NPC][Invasion][Retaliating Minmatar Entities]Dread', 0, 0, 583, 417)),
|
||||
(-96, ('[NPC][Invasion][Retaliating Minmatar Entities]Subcaps', 302, 132, 330, 236)),
|
||||
(-96, ('[NPC][Invasion][Retaliating Minmatar Entities]Subcaps', 302, 136, 328, 234)),
|
||||
(-97, ('[NPC][Mission]Amarr Empire', 4464, 3546, 97, 0)),
|
||||
(-98, ('[NPC][Mission]Caldari State', 0, 2139, 4867, 0)),
|
||||
(-99, ('[NPC][Mission]CONCORD', 336, 134, 212, 412)),
|
||||
@@ -260,6 +260,8 @@ class DamagePattern:
|
||||
line = line.split('#', 1)[0] # allows for comments
|
||||
type, data = line.rsplit('=', 1)
|
||||
type, data = type.strip(), data.split(',')
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
# Data isn't in correct format, continue to next line
|
||||
continue
|
||||
@@ -274,6 +276,8 @@ class DamagePattern:
|
||||
for index, val in enumerate(data):
|
||||
try:
|
||||
fields["%sAmount" % cls.DAMAGE_TYPES[index]] = int(val)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
continue
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ class Fighter(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
self.__itemModifiedAttributes = ModifiedAttributeDict()
|
||||
self.__chargeModifiedAttributes = ModifiedAttributeDict()
|
||||
|
||||
if len(self.abilities) != len(self.item.effects):
|
||||
if {a.effectID for a in self.abilities} != {e.ID for e in self.item.effects.values()}:
|
||||
self.__abilities = []
|
||||
for ability in self.__getAbilities():
|
||||
self.__abilities.append(ability)
|
||||
|
||||
@@ -576,11 +576,15 @@ class Fit:
|
||||
|
||||
if warfareBuffID == 11: # Shield Burst: Active Shielding: Repair Duration/Capacitor
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Shield Operation") or mod.item.requiresSkill(
|
||||
"Shield Emission Systems"), "capacitorNeed", value)
|
||||
lambda mod: mod.item.requiresSkill("Shield Operation") or
|
||||
mod.item.requiresSkill("Shield Emission Systems") or
|
||||
mod.item.requiresSkill("Capital Shield Emission Systems"),
|
||||
"capacitorNeed", value)
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Shield Operation") or mod.item.requiresSkill(
|
||||
"Shield Emission Systems"), "duration", value)
|
||||
lambda mod: mod.item.requiresSkill("Shield Operation") or
|
||||
mod.item.requiresSkill("Shield Emission Systems") or
|
||||
mod.item.requiresSkill("Capital Shield Emission Systems"),
|
||||
"duration", value)
|
||||
|
||||
if warfareBuffID == 12: # Shield Burst: Shield Extension: Shield HP
|
||||
self.ship.boostItemAttr("shieldCapacity", value, stackingPenalties=True)
|
||||
@@ -590,12 +594,16 @@ class Fit:
|
||||
self.ship.boostItemAttr("armor%sDamageResonance" % damageType, value, stackingPenalties=True)
|
||||
|
||||
if warfareBuffID == 14: # Armor Burst: Rapid Repair: Repair Duration/Capacitor
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or
|
||||
mod.item.requiresSkill("Repair Systems"),
|
||||
"capacitorNeed", value)
|
||||
self.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or
|
||||
mod.item.requiresSkill("Repair Systems"),
|
||||
"duration", value)
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or
|
||||
mod.item.requiresSkill("Repair Systems") or
|
||||
mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
|
||||
"capacitorNeed", value)
|
||||
self.modules.filteredItemBoost(
|
||||
lambda mod: mod.item.requiresSkill("Remote Armor Repair Systems") or
|
||||
mod.item.requiresSkill("Repair Systems") or
|
||||
mod.item.requiresSkill("Capital Remote Armor Repair Systems"),
|
||||
"duration", value)
|
||||
|
||||
if warfareBuffID == 15: # Armor Burst: Armor Reinforcement: Armor HP
|
||||
self.ship.boostItemAttr("armorHP", value, stackingPenalties=True)
|
||||
|
||||
@@ -73,6 +73,8 @@ class Mutator(EqBase):
|
||||
self.dynamicAttribute = next(a for a in self.module.mutaplasmid.attributes if a.attributeID == self.attrID)
|
||||
# base attribute links to the base ite's attribute for this mutated definition (contains original, base value)
|
||||
self.baseAttribute = self.module.item.attributes[self.dynamicAttribute.name]
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
self.module = None
|
||||
|
||||
|
||||
@@ -294,6 +294,8 @@ class TargetProfile:
|
||||
line = line.split('#', 1)[0] # allows for comments
|
||||
type, data = line.rsplit('=', 1)
|
||||
type, data = type.strip(), [d.strip() for d in data.split(',')]
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
pyfalog.warning("Data isn't in correct format, continue to next line.")
|
||||
continue
|
||||
@@ -312,6 +314,8 @@ class TargetProfile:
|
||||
try:
|
||||
assert 0 <= val <= 100
|
||||
fields["%sAmount" % cls.DAMAGE_TYPES[index]] = val / 100
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
pyfalog.warning("Caught unhandled exception in import patterns.")
|
||||
continue
|
||||
|
||||
39
eos/utils/pyinst_support.py
Normal file
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Slightly modified version of function taken from here:
|
||||
https://github.com/pyinstaller/pyinstaller/issues/1905#issuecomment-525221546
|
||||
"""
|
||||
|
||||
|
||||
import pkgutil
|
||||
|
||||
|
||||
def iterNamespace(name, path):
|
||||
"""Pyinstaller-compatible namespace iteration.
|
||||
|
||||
Yields the name of all modules found at a given Fully-qualified path.
|
||||
|
||||
To have it running with pyinstaller, it requires to ensure a hook inject the
|
||||
"hidden" modules from your plugins folder inside the executable:
|
||||
|
||||
- if your plugins are under the ``myappname/pluginfolder`` module
|
||||
- create a file ``specs/hook-<myappname.pluginfolder>.py``
|
||||
- content of this file should be:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from PyInstaller.utils.hooks import collect_submodules
|
||||
hiddenimports = collect_submodules('<myappname.pluginfolder>')
|
||||
"""
|
||||
prefix = name + "."
|
||||
for p in pkgutil.iter_modules(path, prefix):
|
||||
yield p[1]
|
||||
|
||||
# special handling when the package is bundled with PyInstaller 3.5
|
||||
# See https://github.com/pyinstaller/pyinstaller/issues/1905#issuecomment-445787510
|
||||
toc = set()
|
||||
for importer in pkgutil.iter_importers(name.partition(".")[0]):
|
||||
if hasattr(importer, 'toc'):
|
||||
toc |= importer.toc
|
||||
for name in toc:
|
||||
if name.startswith(prefix):
|
||||
yield name
|
||||
@@ -26,11 +26,12 @@ VectorDef = namedtuple('VectorDef', ('lengthHandle', 'lengthUnit', 'angleHandle'
|
||||
|
||||
class YDef:
|
||||
|
||||
def __init__(self, handle, unit, label, selectorLabel=None):
|
||||
def __init__(self, handle, unit, label, selectorLabel=None, hidden=False):
|
||||
self.handle = handle
|
||||
self.unit = unit
|
||||
self.label = label
|
||||
self._selectorLabel = selectorLabel
|
||||
self.hidden = hidden
|
||||
|
||||
@property
|
||||
def selectorLabel(self):
|
||||
@@ -53,12 +54,13 @@ class YDef:
|
||||
|
||||
class XDef:
|
||||
|
||||
def __init__(self, handle, unit, label, mainInput, selectorLabel=None):
|
||||
def __init__(self, handle, unit, label, mainInput, selectorLabel=None, hidden=False):
|
||||
self.handle = handle
|
||||
self.unit = unit
|
||||
self.label = label
|
||||
self.mainInput = mainInput
|
||||
self._selectorLabel = selectorLabel
|
||||
self.hidden = hidden
|
||||
|
||||
@property
|
||||
def selectorLabel(self):
|
||||
|
||||
@@ -31,8 +31,8 @@ from .getter import (
|
||||
|
||||
class FitDamageStatsGraph(FitGraph):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._timeCache = TimeCache()
|
||||
self._projectedCache = ProjectedDataCache()
|
||||
|
||||
|
||||
@@ -23,24 +23,6 @@ import math
|
||||
from graphs.data.base import SmoothPointGetter
|
||||
|
||||
|
||||
class Time2SpeedGetter(SmoothPointGetter):
|
||||
|
||||
def _getCommonData(self, miscParams, src, tgt):
|
||||
return {
|
||||
'maxSpeed': src.getMaxVelocity(),
|
||||
'mass': src.item.ship.getModifiedItemAttr('mass'),
|
||||
'agility': src.item.ship.getModifiedItemAttr('agility')}
|
||||
|
||||
def _calculatePoint(self, x, miscParams, src, tgt, commonData):
|
||||
time = x
|
||||
maxSpeed = commonData['maxSpeed']
|
||||
mass = commonData['mass']
|
||||
agility = commonData['agility']
|
||||
# https://wiki.eveuniversity.org/Acceleration#Mathematics_and_formulae
|
||||
speed = maxSpeed * (1 - math.exp((-time * 1000000) / (agility * mass)))
|
||||
return speed
|
||||
|
||||
|
||||
class Time2DistanceGetter(SmoothPointGetter):
|
||||
|
||||
def _getCommonData(self, miscParams, src, tgt):
|
||||
@@ -60,3 +42,62 @@ class Time2DistanceGetter(SmoothPointGetter):
|
||||
distance_0 = maxSpeed * 0 + (maxSpeed * agility * mass * math.exp((-0 * 1000000) / (agility * mass)) / 1000000)
|
||||
distance = distance_t - distance_0
|
||||
return distance
|
||||
|
||||
|
||||
class Time2SpeedGetter(SmoothPointGetter):
|
||||
|
||||
def _getCommonData(self, miscParams, src, tgt):
|
||||
return {
|
||||
'maxSpeed': src.getMaxVelocity(),
|
||||
'mass': src.item.ship.getModifiedItemAttr('mass'),
|
||||
'agility': src.item.ship.getModifiedItemAttr('agility')}
|
||||
|
||||
def _calculatePoint(self, x, miscParams, src, tgt, commonData):
|
||||
time = x
|
||||
maxSpeed = commonData['maxSpeed']
|
||||
mass = commonData['mass']
|
||||
agility = commonData['agility']
|
||||
# https://wiki.eveuniversity.org/Acceleration#Mathematics_and_formulae
|
||||
speed = maxSpeed * (1 - math.exp((-time * 1000000) / (agility * mass)))
|
||||
return speed
|
||||
|
||||
|
||||
class Time2MomentumGetter(Time2SpeedGetter):
|
||||
|
||||
def _calculatePoint(self, x, miscParams, src, tgt, commonData):
|
||||
mass = commonData['mass']
|
||||
speed = Time2SpeedGetter._calculatePoint(
|
||||
self, x=x, miscParams=miscParams,
|
||||
src=src, tgt=tgt, commonData=commonData)
|
||||
momentum = speed * mass
|
||||
return momentum
|
||||
|
||||
|
||||
class Time2BumpSpeedGetter(Time2SpeedGetter):
|
||||
|
||||
def _calculatePoint(self, x, miscParams, src, tgt, commonData):
|
||||
# S. Santorine, Ship Motion in EVE-Online, p3, Collisions & Bumping section
|
||||
# https://docs.google.com/document/d/1rwVWjTvzVdPEFETf0vwm649AFb4bgRBaNLpRPaoB03o
|
||||
# Internally, Santorine's formulas are using millions of kilograms, so we normalize to them here
|
||||
bumperMass = commonData['mass'] / 10 ** 6
|
||||
bumperSpeed = Time2SpeedGetter._calculatePoint(
|
||||
self, x=x, miscParams=miscParams,
|
||||
src=src, tgt=tgt, commonData=commonData)
|
||||
tgtMass = miscParams['tgtMass'] / 10 ** 6
|
||||
tgtSpeed = (2 * bumperSpeed * bumperMass) / (bumperMass + tgtMass)
|
||||
return tgtSpeed
|
||||
|
||||
|
||||
class Time2BumpDistanceGetter(Time2BumpSpeedGetter):
|
||||
|
||||
def _calculatePoint(self, x, miscParams, src, tgt, commonData):
|
||||
# S. Santorine, Ship Motion in EVE-Online, p3, Collisions & Bumping section
|
||||
# https://docs.google.com/document/d/1rwVWjTvzVdPEFETf0vwm649AFb4bgRBaNLpRPaoB03o
|
||||
# Internally, Santorine's formulas are using millions of kilograms, so we normalize to them here
|
||||
tgtMass = miscParams['tgtMass'] / 10 ** 6
|
||||
tgtInertia = miscParams['tgtInertia']
|
||||
tgtSpeed = Time2BumpSpeedGetter._calculatePoint(
|
||||
self, x=x, miscParams=miscParams,
|
||||
src=src, tgt=tgt, commonData=commonData)
|
||||
tgtDistance = tgtSpeed * tgtMass * tgtInertia
|
||||
return tgtDistance
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
|
||||
from graphs.data.base import FitGraph, XDef, YDef, Input
|
||||
from .getter import Time2SpeedGetter, Time2DistanceGetter
|
||||
from .getter import Time2SpeedGetter, Time2DistanceGetter, Time2MomentumGetter, Time2BumpSpeedGetter, Time2BumpDistanceGetter
|
||||
|
||||
|
||||
class FitMobilityGraph(FitGraph):
|
||||
@@ -30,12 +30,26 @@ class FitMobilityGraph(FitGraph):
|
||||
xDefs = [XDef(handle='time', unit='s', label='Time', mainInput=('time', 's'))]
|
||||
yDefs = [
|
||||
YDef(handle='speed', unit='m/s', label='Speed'),
|
||||
YDef(handle='distance', unit='km', label='Distance')]
|
||||
inputs = [Input(handle='time', unit='s', label='Time', iconID=1392, defaultValue=10, defaultRange=(0, 30))]
|
||||
YDef(handle='distance', unit='km', label='Distance'),
|
||||
YDef(handle='momentum', unit='Gkg⋅m/s', label='Momentum'),
|
||||
YDef(handle='bumpSpeed', unit='m/s', label='Target speed', selectorLabel='Bump speed'),
|
||||
YDef(handle='bumpDistance', unit='km', label='Target distance traveled', selectorLabel='Bump distance')]
|
||||
inputs = [
|
||||
Input(handle='time', unit='s', label='Time', iconID=1392, defaultValue=10, defaultRange=(0, 30)),
|
||||
# Default values in target fields correspond to a random carrier/fax
|
||||
Input(handle='tgtMass', unit='Mkg', label='Target mass', iconID=76, defaultValue=1300, defaultRange=(100, 2500), conditions=[(None, ('bumpSpeed', 'm/s')), (None, ('bumpDistance', 'km'))], secondaryTooltip='Defined in millions of kilograms'),
|
||||
Input(handle='tgtInertia', unit=None, label='Target inertia factor', iconID=1401, defaultValue=0.015, defaultRange=(0.03, 0.1), conditions=[(None, ('bumpDistance', 'km'))], secondaryTooltip='Inertia Modifier attribute value of the target ship')]
|
||||
srcExtraCols = ('Speed', 'Agility')
|
||||
|
||||
# Calculation stuff
|
||||
_normalizers = {('tgtMass', 'Mkg'): lambda v, src, tgt: None if v is None else v * 10 ** 6}
|
||||
_getters = {
|
||||
('time', 'speed'): Time2SpeedGetter,
|
||||
('time', 'distance'): Time2DistanceGetter}
|
||||
_denormalizers = {('distance', 'km'): lambda v, src, tgt: v / 1000}
|
||||
('time', 'distance'): Time2DistanceGetter,
|
||||
('time', 'momentum'): Time2MomentumGetter,
|
||||
('time', 'bumpSpeed'): Time2BumpSpeedGetter,
|
||||
('time', 'bumpDistance'): Time2BumpDistanceGetter}
|
||||
_denormalizers = {
|
||||
('distance', 'km'): lambda v, src, tgt: v / 1000,
|
||||
('momentum', 'Gkg⋅m/s'): lambda v, src, tgt: v / 10 ** 9,
|
||||
('bumpDistance', 'km'): lambda v, src, tgt: v / 1000}
|
||||
|
||||
@@ -26,8 +26,8 @@ from .getter import Distance2RpsGetter, Distance2RepAmountGetter, Time2RpsGetter
|
||||
|
||||
class FitRemoteRepsGraph(FitGraph):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._timeCache = TimeCache()
|
||||
|
||||
def _clearInternalCache(self, reason, extraData):
|
||||
|
||||
@@ -27,6 +27,10 @@ from .getter import (
|
||||
|
||||
class FitShieldRegenGraph(FitGraph):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.isEffective = gui.mainFrame.MainFrame.getInstance().statsPane.nameViewMap['resistancesViewFull'].showEffective
|
||||
|
||||
# UI stuff
|
||||
internalName = 'shieldRegenGraph'
|
||||
name = 'Shield Regeneration'
|
||||
@@ -73,7 +77,3 @@ class FitShieldRegenGraph(FitGraph):
|
||||
('shieldAmount', '%'): lambda v, src, tgt: v * 100 / src.item.ship.getModifiedItemAttr('shieldCapacity'),
|
||||
('shieldAmount', 'EHP'): lambda v, src, tgt: src.item.damagePattern.effectivify(src.item, v, 'shield'),
|
||||
('shieldRegen', 'EHP/s'): lambda v, src, tgt: src.item.damagePattern.effectivify(src.item, v, 'shield')}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.isEffective = gui.mainFrame.MainFrame.getInstance().statsPane.nameViewMap['resistancesViewFull'].showEffective
|
||||
|
||||
@@ -26,8 +26,8 @@ from .getter import AU_METERS, Distance2TimeGetter
|
||||
|
||||
class FitWarpTimeGraph(FitGraph):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._subspeedCache = SubwarpSpeedCache()
|
||||
|
||||
def _clearInternalCache(self, reason, extraData):
|
||||
|
||||
@@ -54,6 +54,8 @@ try:
|
||||
except ImportError as e:
|
||||
pyfalog.warning('Matplotlib failed to import. Likely missing or incompatible version.')
|
||||
graphFrame_enabled = False
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception:
|
||||
# We can get exceptions deep within matplotlib. Catch those. See GH #1046
|
||||
tb = traceback.format_exc()
|
||||
@@ -71,6 +73,8 @@ class GraphCanvasPanel(wx.Panel):
|
||||
# Remove matplotlib font cache, see #234
|
||||
try:
|
||||
cache_dir = mpl._get_cachedir()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
cache_dir = os.path.expanduser(os.path.join('~', '.matplotlib'))
|
||||
cache_file = os.path.join(cache_dir, 'fontList.cache')
|
||||
@@ -168,6 +172,8 @@ class GraphCanvasPanel(wx.Panel):
|
||||
legendData.append((color, lineStyle, source.shortName))
|
||||
else:
|
||||
legendData.append((color, lineStyle, '{} vs {}'.format(source.shortName, target.shortName)))
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception:
|
||||
pyfalog.warning('Failed to plot "{}" vs "{}"'.format(source.name, '' if target is None else target.name))
|
||||
self.canvas.draw()
|
||||
@@ -241,6 +247,8 @@ class GraphCanvasPanel(wx.Panel):
|
||||
src=source,
|
||||
tgt=target)
|
||||
addYMark(y)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception:
|
||||
pyfalog.warning('Failed to get X mark for "{}" vs "{}"'.format(source.name, '' if target is None else target.name))
|
||||
# Silently skip this mark, otherwise other marks and legend display will fail
|
||||
|
||||
@@ -295,12 +295,16 @@ class GraphControlPanel(wx.Panel):
|
||||
|
||||
self.ySubSelection.Clear()
|
||||
for yDef in view.yDefs:
|
||||
if yDef.hidden and not self.graphFrame.includeHidden:
|
||||
continue
|
||||
self.ySubSelection.Append(self.formatLabel(yDef, selector=True), yDef)
|
||||
self.ySubSelection.Enable(len(view.yDefs) > 1)
|
||||
self.ySubSelection.SetSelection(selectedY)
|
||||
|
||||
self.xSubSelection.Clear()
|
||||
for xDef in view.xDefs:
|
||||
if xDef.hidden and not self.graphFrame.includeHidden:
|
||||
continue
|
||||
self.xSubSelection.Append(self.formatLabel(xDef, selector=True), xDef)
|
||||
self.xSubSelection.Enable(len(view.xDefs) > 1)
|
||||
self.xSubSelection.SetSelection(selectedX)
|
||||
|
||||
@@ -50,6 +50,7 @@ class GraphFrame(AuxiliaryFrame):
|
||||
|
||||
super().__init__(parent, title='Graphs', size=(520, 390), resizeable=True)
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.includeHidden = includeHidden
|
||||
|
||||
self.SetIcon(wx.Icon(BitmapLoader.getBitmap('graphs_small', 'gui')))
|
||||
|
||||
@@ -74,7 +75,7 @@ class GraphFrame(AuxiliaryFrame):
|
||||
|
||||
# Setup - graph selector
|
||||
for view in FitGraph.views:
|
||||
if view.hidden and not includeHidden:
|
||||
if view.hidden and not self.includeHidden:
|
||||
continue
|
||||
self.graphSelection.Append(view.name, view())
|
||||
self.graphSelection.SetSelection(0)
|
||||
|
||||
@@ -316,7 +316,7 @@ class ImplantDisplay(d.Display):
|
||||
implants.append(implant)
|
||||
return implants
|
||||
|
||||
def addImplantSet(self, impSet):
|
||||
def addImplants(self, implants):
|
||||
self.mainFrame.command.Submit(cmd.GuiAddImplantSetCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
itemIDs=[i.itemID for i in impSet.implants]))
|
||||
itemIDs=[i.itemID for i in implants]))
|
||||
|
||||
@@ -121,18 +121,18 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
|
||||
|
||||
# Expressions for matching when detecting effects we're looking for
|
||||
if incursions:
|
||||
validgroups = ("Incursion ship attributes effects",
|
||||
"Invasion Effects")
|
||||
validgroups = ("Sansha Incursion",
|
||||
"Triglavian Invasion")
|
||||
else:
|
||||
validgroups = ("Black Hole Effect Beacon",
|
||||
"Cataclysmic Variable Effect Beacon",
|
||||
"Magnetar Effect Beacon",
|
||||
"Pulsar Effect Beacon",
|
||||
"Red Giant Beacon",
|
||||
"Wolf Rayet Effect Beacon")
|
||||
validgroups = ("Black Hole",
|
||||
"Cataclysmic Variable",
|
||||
"Magnetar",
|
||||
"Pulsar",
|
||||
"Red Giant",
|
||||
"Wolf Rayet")
|
||||
|
||||
# Stuff we don't want to see in names
|
||||
garbages = ("Effects?", "Beacon", "ship attributes effects")
|
||||
garbages = ("System Effects", "Effects")
|
||||
|
||||
# Get group with all the system-wide beacons
|
||||
grp = sMkt.getGroup("Effect Beacon")
|
||||
@@ -142,7 +142,7 @@ class AddEnvironmentEffect(ContextMenuUnconditional):
|
||||
# Check if it belongs to any valid group
|
||||
for group in validgroups:
|
||||
# Check beginning of the name only
|
||||
if re.match(group, beacon.name):
|
||||
if re.search(group, beacon.name):
|
||||
# Get full beacon name
|
||||
beaconname = beacon.name
|
||||
for garbage in garbages:
|
||||
|
||||
@@ -2,17 +2,19 @@
|
||||
import wx
|
||||
|
||||
from gui.contextMenu import ContextMenuUnconditional
|
||||
from service.implantSet import ImplantSets as s_ImplantSets
|
||||
from service.market import Market
|
||||
from service.implantSet import ImplantSets as UserImplantSets
|
||||
from service.precalcImplantSet import PrecalcedImplantSets
|
||||
|
||||
|
||||
class ImplantSetApply(ContextMenuUnconditional):
|
||||
|
||||
def display(self, callingWindow, srcContext):
|
||||
|
||||
sIS = s_ImplantSets.getInstance()
|
||||
implantSets = sIS.getImplantSetList()
|
||||
self.userImplantSets = UserImplantSets.getInstance().getImplantSetList()
|
||||
self.structedImplantSets = PrecalcedImplantSets.getStructuredSets()
|
||||
|
||||
if len(implantSets) == 0:
|
||||
if len(self.userImplantSets) == 0 and len(self.structedImplantSets) == 0:
|
||||
return False
|
||||
|
||||
return srcContext in ("implantItemMisc", "implantEditor")
|
||||
@@ -20,34 +22,87 @@ class ImplantSetApply(ContextMenuUnconditional):
|
||||
def getText(self, callingWindow, context):
|
||||
return "Apply Implant Set"
|
||||
|
||||
def getSubMenu(self, callingWindow, context, rootMenu, i, pitem):
|
||||
m = wx.Menu()
|
||||
bindmenu = rootMenu if "wxMSW" in wx.PlatformInfo else m
|
||||
def _addSeparator(self, m, text):
|
||||
id_ = ContextMenuUnconditional.nextID()
|
||||
m.Append(id_, '─ %s ─' % text)
|
||||
m.Enable(id_, False)
|
||||
|
||||
sIS = s_ImplantSets.getInstance()
|
||||
implantSets = sIS.getImplantSetList()
|
||||
def _addSet(self, parentMenu, profile, name):
|
||||
id = ContextMenuUnconditional.nextID()
|
||||
self.eventSetMap[id] = profile
|
||||
menuItem = wx.MenuItem(parentMenu, id, name)
|
||||
parentMenu.Bind(wx.EVT_MENU, self.handleSelection, menuItem)
|
||||
return menuItem
|
||||
|
||||
def _addCategory(self, parentMenu, name):
|
||||
id = ContextMenuUnconditional.nextID()
|
||||
menuItem = wx.MenuItem(parentMenu, id, name)
|
||||
parentMenu.Bind(wx.EVT_MENU, self.handleSelection, menuItem)
|
||||
return menuItem
|
||||
|
||||
def _gradeSorter(self, item):
|
||||
order = ['low-grade', 'mid-grade', 'high-grade']
|
||||
try:
|
||||
pos = order.index(item.lower())
|
||||
except IndexError:
|
||||
pos = len(order)
|
||||
return pos, item
|
||||
|
||||
def getSubMenu(self, callingWindow, context, rootMenu, i, pitem):
|
||||
msw = "wxMSW" in wx.PlatformInfo
|
||||
menu_lvl1 = wx.Menu()
|
||||
|
||||
self.context = context
|
||||
self.callingWindow = callingWindow
|
||||
|
||||
self.idmap = {}
|
||||
self.eventSetMap = {}
|
||||
|
||||
for set in sorted(implantSets, key=lambda i: i.name):
|
||||
id = ContextMenuUnconditional.nextID()
|
||||
mitem = wx.MenuItem(rootMenu, id, set.name)
|
||||
bindmenu.Bind(wx.EVT_MENU, self.handleSelection, mitem)
|
||||
self.idmap[id] = set
|
||||
m.Append(mitem)
|
||||
# Auto-generated sets
|
||||
for setName in sorted(self.structedImplantSets):
|
||||
setData = self.structedImplantSets[setName]
|
||||
if len(setData) == 1:
|
||||
for implantIDs in setData.values():
|
||||
menuitem_lvl1 = self._addSet(rootMenu, implantIDs, setName)
|
||||
menu_lvl1.Append(menuitem_lvl1)
|
||||
else:
|
||||
menuitem_lvl1 = self._addCategory(rootMenu, setName)
|
||||
menu_lvl2 = wx.Menu()
|
||||
for gradeName in sorted(setData, key=self._gradeSorter):
|
||||
implantIDs = setData[gradeName]
|
||||
menuitem_lvl2 = self._addSet(rootMenu if msw else menu_lvl1, implantIDs, gradeName)
|
||||
menu_lvl2.Append(menuitem_lvl2)
|
||||
menu_lvl2.Bind(wx.EVT_MENU, self.handleSelection)
|
||||
menuitem_lvl1.SetSubMenu(menu_lvl2)
|
||||
menu_lvl1.Append(menuitem_lvl1)
|
||||
|
||||
return m
|
||||
# Separator
|
||||
if self.userImplantSets and self.structedImplantSets:
|
||||
menu_lvl1.AppendSeparator()
|
||||
|
||||
# Saved sets
|
||||
if self.userImplantSets:
|
||||
menuitem_lvl1 = self._addCategory(rootMenu, 'Saved Sets')
|
||||
menu_lvl2 = wx.Menu()
|
||||
for implantSet in sorted(self.userImplantSets, key=lambda i: i.name):
|
||||
menuitem_lvl2 = self._addSet(rootMenu if msw else menu_lvl1, implantSet, implantSet.name)
|
||||
menu_lvl2.Append(menuitem_lvl2)
|
||||
menu_lvl2.Bind(wx.EVT_MENU, self.handleSelection)
|
||||
menuitem_lvl1.SetSubMenu(menu_lvl2)
|
||||
menu_lvl1.Append(menuitem_lvl1)
|
||||
|
||||
menu_lvl1.Bind(wx.EVT_MENU, self.handleSelection)
|
||||
return menu_lvl1
|
||||
|
||||
def handleSelection(self, event):
|
||||
impSet = self.idmap.get(event.Id, None)
|
||||
impSet = self.eventSetMap.get(event.Id, None)
|
||||
if impSet is None:
|
||||
event.Skip()
|
||||
return
|
||||
|
||||
self.callingWindow.addImplantSet(impSet)
|
||||
if isinstance(impSet, str):
|
||||
implants = PrecalcedImplantSets.stringToImplants(impSet)
|
||||
else:
|
||||
implants = impSet.implants
|
||||
self.callingWindow.addImplants(implants)
|
||||
|
||||
|
||||
ImplantSetApply.register()
|
||||
|
||||
@@ -26,7 +26,7 @@ class TargetProfileAdder(ContextMenuUnconditional):
|
||||
return 'Add Target Profile'
|
||||
|
||||
def handleProfileAdd(self, event):
|
||||
profile = self.profileEventMap.get(event.Id, False)
|
||||
profile = self.eventProfileMap.get(event.Id, False)
|
||||
if profile is False:
|
||||
event.Skip()
|
||||
return
|
||||
@@ -34,7 +34,7 @@ class TargetProfileAdder(ContextMenuUnconditional):
|
||||
|
||||
def _addProfile(self, parentMenu, profile, name):
|
||||
id = ContextMenuUnconditional.nextID()
|
||||
self.profileEventMap[id] = profile
|
||||
self.eventProfileMap[id] = profile
|
||||
menuItem = wx.MenuItem(parentMenu, id, name)
|
||||
parentMenu.Bind(wx.EVT_MENU, self.handleProfileAdd, menuItem)
|
||||
return menuItem
|
||||
@@ -51,7 +51,7 @@ class TargetProfileAdder(ContextMenuUnconditional):
|
||||
profiles = list(chain(sTR.getBuiltinTargetProfileList(), sTR.getUserTargetProfileList()))
|
||||
profiles.sort(key=lambda p: smartSort(p.fullName))
|
||||
|
||||
self.profileEventMap = {}
|
||||
self.eventProfileMap = {}
|
||||
items = (OrderedDict(), OrderedDict())
|
||||
for profile in profiles:
|
||||
container = items
|
||||
|
||||
@@ -112,6 +112,8 @@ class ItemAffectedBy(wx.Panel):
|
||||
else:
|
||||
try:
|
||||
self.affectedBy.CollapseAll()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -171,7 +173,7 @@ class ItemAffectedBy(wx.Panel):
|
||||
|
||||
def sortAttrDisplayName(self, attr):
|
||||
info = self.stuff.item.attributes.get(attr)
|
||||
if info and info.displayName != "":
|
||||
if info and info.displayName:
|
||||
return info.displayName
|
||||
|
||||
return attr
|
||||
@@ -251,7 +253,7 @@ class ItemAffectedBy(wx.Panel):
|
||||
|
||||
for attrName in attrOrder:
|
||||
attrInfo = self.stuff.item.attributes.get(attrName)
|
||||
displayName = attrInfo.displayName if attrInfo and attrInfo.displayName != "" else attrName
|
||||
displayName = attrInfo.displayName if attrInfo and attrInfo.displayName else attrName
|
||||
|
||||
if attrInfo:
|
||||
if attrInfo.iconID is not None:
|
||||
@@ -444,7 +446,7 @@ class ItemAffectedBy(wx.Panel):
|
||||
attrModifier = "-"
|
||||
attrAmount = -attrAmount
|
||||
|
||||
attributes.append((attrName, (displayName if displayName != "" else attrName), attrModifier,
|
||||
attributes.append((attrName, (displayName if displayName else attrName), attrModifier,
|
||||
attrAmount, penalized, attrIcon))
|
||||
|
||||
attrSorted = sorted(attributes, key=lambda attribName: attribName[0])
|
||||
@@ -454,14 +456,14 @@ class ItemAffectedBy(wx.Panel):
|
||||
if self.showRealNames:
|
||||
display = "%s %s %.2f %s" % (attrName, attrModifier, attrAmount, penalized)
|
||||
saved = "%s %s %.2f %s" % (
|
||||
displayName if displayName != "" else attrName,
|
||||
displayName if displayName else attrName,
|
||||
attrModifier,
|
||||
attrAmount,
|
||||
penalized
|
||||
)
|
||||
else:
|
||||
display = "%s %s %.2f %s" % (
|
||||
displayName if displayName != "" else attrName,
|
||||
displayName if displayName else attrName,
|
||||
attrModifier,
|
||||
attrAmount,
|
||||
penalized
|
||||
|
||||
@@ -86,6 +86,8 @@ class ItemProperties(wx.Panel):
|
||||
valueUnit = str(value)
|
||||
|
||||
self.paramList.SetItem(index, 1, valueUnit)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
# TODO: Add logging to this.
|
||||
# We couldn't get a property for some reason. Skip it for now.
|
||||
|
||||
@@ -49,8 +49,6 @@ class ItemView(Display):
|
||||
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.itemActivated)
|
||||
self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag)
|
||||
|
||||
# Make reverse map, used by sorter
|
||||
self.metaMap = self.makeReverseMetaMap()
|
||||
self.active = []
|
||||
|
||||
def delaySearch(self, evt):
|
||||
@@ -180,7 +178,7 @@ class ItemView(Display):
|
||||
return
|
||||
|
||||
self.marketBrowser.mode = 'search'
|
||||
self.sMkt.searchItems(search, self.populateSearch)
|
||||
self.sMkt.searchItems(search, self.populateSearch, 'market')
|
||||
|
||||
def clearSearch(self, event=None):
|
||||
# Wipe item store and update everything to accomodate with it
|
||||
@@ -214,7 +212,7 @@ class ItemView(Display):
|
||||
parentname = sMkt.getParentItemByItem(item).name
|
||||
# Get position of market group
|
||||
metagrpid = sMkt.getMetaGroupIdByItem(item)
|
||||
metatab = self.metaMap.get(metagrpid)
|
||||
metatab = sMkt.META_MAP_REVERSE_INDICES.get(metagrpid)
|
||||
metalvl = item.metaLevel or 0
|
||||
|
||||
return catname, mktgrpid, parentname, metatab, metalvl, item.name
|
||||
@@ -259,18 +257,6 @@ class ItemView(Display):
|
||||
|
||||
Display.refresh(self, items)
|
||||
|
||||
def makeReverseMetaMap(self):
|
||||
"""
|
||||
Form map which tells in which tab items of given metagroup are located
|
||||
"""
|
||||
revmap = {}
|
||||
i = 0
|
||||
for mgids in self.sMkt.META_MAP.values():
|
||||
for mgid in mgids:
|
||||
revmap[mgid] = i
|
||||
i += 1
|
||||
return revmap
|
||||
|
||||
def columnBackground(self, colItem, item):
|
||||
if self.sFit.serviceFittingOptions["colorFitBySlot"]:
|
||||
return slotColourMap.get(Module.calculateSlot(item)) or self.GetBackgroundColour()
|
||||
|
||||
@@ -63,6 +63,8 @@ class MarketTree(wx.TreeCtrl):
|
||||
iconId = self.addImage(sMkt.getIconByMarketGroup(childMktGrp))
|
||||
try:
|
||||
childId = self.AppendItem(root, childMktGrp.name, iconId, data=childMktGrp.ID)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as e:
|
||||
pyfalog.debug("Error appending item.")
|
||||
pyfalog.debug(e)
|
||||
|
||||
@@ -25,7 +25,7 @@ class PFGeneralPref(PreferenceView):
|
||||
self.stTitle.Wrap(-1)
|
||||
self.stTitle.SetFont(wx.Font(12, 70, 90, 90, False, wx.EmptyString))
|
||||
mainSizer.Add(self.stTitle, 0, wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
|
||||
helpCursor = wx.Cursor(wx.CURSOR_QUESTION_ARROW)
|
||||
|
||||
self.m_staticline1 = wx.StaticLine(panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
|
||||
|
||||
@@ -608,6 +608,18 @@ class Miscellanea(ViewColumn):
|
||||
shield_hp = stuff.getModifiedItemAttr("shieldBonus", 0)
|
||||
hp = max(stuff_hp, armor_hp * cycles, capacitor_hp * cycles, shield_hp * cycles, 0)
|
||||
|
||||
nonChargedMap = {
|
||||
"Ancillary Remote Armor Repairer": ("armor", "Armor repaired per second"),
|
||||
"Ancillary Remote Shield Booster": ("shield", "Shield transferred per second")}
|
||||
if not cycles and itemGroup in nonChargedMap:
|
||||
rps = stuff.getRemoteReps(ignoreState=True)
|
||||
rps = getattr(rps, nonChargedMap[itemGroup][0])
|
||||
if not rps:
|
||||
return "", None
|
||||
text = "{0}/s".format(formatAmount(rps, 3, 0, 3, forceSign=True))
|
||||
tooltip = nonChargedMap[itemGroup][1]
|
||||
return text, tooltip
|
||||
|
||||
if not hp or not cycleTime or not cycles:
|
||||
return "", None
|
||||
|
||||
|
||||
@@ -66,6 +66,8 @@ class FitSpawner(gui.multiSwitch.TabSpawner):
|
||||
self.multiSwitch.SetSelection(index)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitIDs=(event.fitID,)))
|
||||
break
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as e:
|
||||
pyfalog.critical("Caught exception in fitSelected")
|
||||
pyfalog.critical(e)
|
||||
@@ -812,6 +814,8 @@ class FittingView(d.Display):
|
||||
if self and not self.IsShown():
|
||||
try:
|
||||
self.MakeSnapshot()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as e:
|
||||
pyfalog.critical("Failed to make snapshot")
|
||||
pyfalog.critical(e)
|
||||
@@ -837,6 +841,8 @@ class FittingView(d.Display):
|
||||
sFit = Fit.getInstance()
|
||||
try:
|
||||
fit = sFit.getFit(self.activeFitID)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as e:
|
||||
pyfalog.critical("Failed to get fit")
|
||||
pyfalog.critical(e)
|
||||
|
||||
@@ -309,7 +309,7 @@ class ItemView(d.Display):
|
||||
self.clearSearch()
|
||||
return
|
||||
|
||||
sMkt.searchItems(search, self.populateSearch, ["Implant"])
|
||||
sMkt.searchItems(search, self.populateSearch, 'implants')
|
||||
|
||||
def populateSearch(self, items):
|
||||
if not self.IsShown():
|
||||
|
||||
@@ -475,6 +475,8 @@ class SkillTreeView(wx.Panel):
|
||||
if skill:
|
||||
skill.setLevel(level, ignoreRestrict=True)
|
||||
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as e:
|
||||
pyfalog.error(e)
|
||||
with wx.MessageDialog(self, "There was an error importing skills, please see log file", "Error", wx.ICON_ERROR) as dlg:
|
||||
@@ -727,12 +729,12 @@ class ImplantEditorView(BaseImplantEditorView):
|
||||
|
||||
sChar.removeImplant(char.ID, implant)
|
||||
|
||||
def addImplantSet(self, impSet):
|
||||
def addImplants(self, implants):
|
||||
charEditor = self.Parent.Parent
|
||||
char = charEditor.entityEditor.getActiveEntity()
|
||||
|
||||
sChar = Character.getInstance()
|
||||
for implant in impSet.implants:
|
||||
for implant in implants:
|
||||
sChar.addImplant(char.ID, implant.item.ID)
|
||||
|
||||
wx.PostEvent(charEditor, GE.CharChanged())
|
||||
@@ -839,7 +841,7 @@ class APIView(wx.Panel):
|
||||
|
||||
def getActiveCharacter(self):
|
||||
selection = self.charChoice.GetCurrentSelection()
|
||||
return self.charChoice.GetClientData(selection) if selection is not -1 else None
|
||||
return self.charChoice.GetClientData(selection) if selection != -1 else None
|
||||
|
||||
def ssoListChanged(self, event):
|
||||
if not self: # todo: fix event not unbinding properly
|
||||
|
||||
@@ -122,7 +122,7 @@ class CharacterSelection(wx.Panel):
|
||||
|
||||
def getActiveCharacter(self):
|
||||
selection = self.charChoice.GetCurrentSelection()
|
||||
return self.charChoice.GetClientData(selection) if selection is not -1 else None
|
||||
return self.charChoice.GetClientData(selection) if selection != -1 else None
|
||||
|
||||
def refreshCharacterList(self, event=None):
|
||||
choice = self.charChoice
|
||||
@@ -303,7 +303,6 @@ class CharacterSelection(wx.Panel):
|
||||
if tabulationLevel == 0:
|
||||
for item, subReqs in reqs.items():
|
||||
skillsMap = self._buildSkillsTooltipCondensed(subReqs, item.name, 1, skillsMap)
|
||||
sorted(skillsMap, key=skillsMap.get)
|
||||
else:
|
||||
for name, info in reqs.items():
|
||||
level, ID, more = info
|
||||
@@ -323,3 +322,25 @@ class CharacterSelection(wx.Panel):
|
||||
skillsMap = self._buildSkillsTooltipCondensed(more, currItem, tabulationLevel + 1, skillsMap)
|
||||
|
||||
return skillsMap
|
||||
|
||||
def _buildSkillsTooltipSuperCondensed(self, reqs, currItem="", tabulationLevel=0, skillsMap=None):
|
||||
allReqs = {}
|
||||
implicitReqs = {}
|
||||
|
||||
def traverseReqs(itemReqs, topLevel=True):
|
||||
for skillName, (skillLevel, skillTypeID, subReqs) in itemReqs.items():
|
||||
if (skillTypeID, skillName) not in allReqs or allReqs[(skillTypeID, skillName)] < skillLevel:
|
||||
allReqs[(skillTypeID, skillName)] = skillLevel
|
||||
if not topLevel and (skillTypeID not in implicitReqs or implicitReqs[skillTypeID] < skillLevel):
|
||||
implicitReqs[skillTypeID] = skillLevel
|
||||
traverseReqs(subReqs, topLevel=False)
|
||||
|
||||
for item, itemReqs in reqs.items():
|
||||
traverseReqs(itemReqs)
|
||||
|
||||
newReqs = {}
|
||||
for (skillTypeID, skillName), skillLevel in allReqs.items():
|
||||
if skillTypeID not in implicitReqs or implicitReqs[skillTypeID] < skillLevel:
|
||||
newReqs[skillName] = skillLevel, skillTypeID
|
||||
|
||||
return newReqs
|
||||
|
||||
@@ -1138,6 +1138,8 @@ class _TabsContainer(wx.Panel):
|
||||
self.preview_tab = tab
|
||||
self.preview_timer.Start(500, True)
|
||||
break
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@@ -125,6 +125,8 @@ class EveFittings(AuxiliaryFrame):
|
||||
# Can't do this in a finally because then it obscures the message dialog
|
||||
del waitDialog # noqa: F821
|
||||
ESIExceptionHandler(self, ex)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as ex:
|
||||
del waitDialog # noqa: F821
|
||||
raise ex
|
||||
@@ -302,6 +304,8 @@ class ExportToEve(AuxiliaryFrame):
|
||||
except APIException as ex:
|
||||
try:
|
||||
ESIExceptionHandler(self, ex)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as ex:
|
||||
self.statusbar.SetStatusText("ERROR", 0)
|
||||
self.statusbar.SetStatusText("{} - {}".format(res.status_code, res.reason), 1)
|
||||
@@ -381,6 +385,8 @@ class SsoCharacterMgmt(AuxiliaryFrame):
|
||||
try:
|
||||
sEsi = Esi.getInstance()
|
||||
sEsi.login()
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as ex:
|
||||
ESIServerExceptionHandler(self, ex)
|
||||
|
||||
@@ -457,6 +463,8 @@ class FittingsTreeView(wx.Panel):
|
||||
cargo = Cargo(getItem(item['type_id']))
|
||||
cargo.amount = item['quantity']
|
||||
list.append(cargo)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as e:
|
||||
pyfalog.critical("Exception caught in displayFit")
|
||||
pyfalog.critical(e)
|
||||
|
||||
@@ -99,12 +99,14 @@ class PFPanel(wx.Panel):
|
||||
|
||||
|
||||
class OpenFitsThread(threading.Thread):
|
||||
|
||||
def __init__(self, fits, callback):
|
||||
threading.Thread.__init__(self)
|
||||
self.name = "LoadingOpenFits"
|
||||
self.mainFrame = MainFrame.getInstance()
|
||||
self.callback = callback
|
||||
self.fits = fits
|
||||
self.running = True
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
@@ -118,10 +120,15 @@ class OpenFitsThread(threading.Thread):
|
||||
# We use 1 for all fits except the last one where we use 2 so that we
|
||||
# have correct calculations displayed at startup
|
||||
for fitID in self.fits[:-1]:
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID, startup=1))
|
||||
if self.running:
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=fitID, startup=1))
|
||||
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=self.fits[-1], startup=2))
|
||||
wx.CallAfter(self.callback)
|
||||
if self.running:
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=self.fits[-1], startup=2))
|
||||
wx.CallAfter(self.callback)
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
|
||||
# todo: include IPortUser again
|
||||
@@ -251,10 +258,12 @@ class MainFrame(wx.Frame):
|
||||
fit = sFit.getFit(id, basic=True)
|
||||
if fit is None:
|
||||
fits.remove(id)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
fits.remove(id)
|
||||
|
||||
if not self.prevOpenFits['enabled'] or len(fits) is 0:
|
||||
if not self.prevOpenFits['enabled'] or len(fits) == 0:
|
||||
# add blank page if there are no fits to be loaded
|
||||
self.fitMultiSwitch.AddPage()
|
||||
return
|
||||
@@ -669,8 +678,8 @@ class MainFrame(wx.Frame):
|
||||
|
||||
def toggleOverrides(self, event):
|
||||
ModifiedAttributeDict.overrides_enabled = not ModifiedAttributeDict.overrides_enabled
|
||||
|
||||
wx.PostEvent(self, GE.FitChanged(fitIDs=(self.getActiveFit(),)))
|
||||
changedFitIDs = Fit.getInstance().processOverrideToggle()
|
||||
wx.PostEvent(self, GE.FitChanged(fitIDs=changedFitIDs))
|
||||
menu = self.GetMenuBar()
|
||||
menu.SetLabel(menu.toggleOverridesId,
|
||||
"&Turn Overrides Off" if ModifiedAttributeDict.overrides_enabled else "&Turn Overrides On")
|
||||
@@ -747,9 +756,12 @@ class MainFrame(wx.Frame):
|
||||
activeFit = self.getActiveFit()
|
||||
try:
|
||||
importType, importData = Port().importFitFromBuffer(clipboard, activeFit)
|
||||
if importType == "MutatedItem":
|
||||
# we've imported an Abyssal module, need to fire off the command to add it to the fit
|
||||
self.command.Submit(cmd.GuiImportLocalMutatedModuleCommand(activeFit, *importData[0]))
|
||||
if importType == "FittingItem":
|
||||
baseItem, mutaplasmidItem, mutations = importData[0]
|
||||
if mutaplasmidItem:
|
||||
self.command.Submit(cmd.GuiImportLocalMutatedModuleCommand(activeFit, baseItem, mutaplasmidItem, mutations))
|
||||
else:
|
||||
self.command.Submit(cmd.GuiAddLocalModuleCommand(activeFit, baseItem.ID))
|
||||
return
|
||||
if importType == "AdditionsDrones":
|
||||
if self.command.Submit(cmd.GuiImportLocalDronesCommand(activeFit, [(i.ID, a) for i, a in importData[0]])):
|
||||
@@ -771,6 +783,8 @@ class MainFrame(wx.Frame):
|
||||
if self.command.Submit(cmd.GuiImportCargosCommand(activeFit, [(i.ID, a) for i, a in importData[0]])):
|
||||
self.additionsPane.select("Cargo")
|
||||
return
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
pyfalog.error("Attempt to import failed:\n{0}", clipboard)
|
||||
else:
|
||||
|
||||
@@ -67,7 +67,8 @@ class DmgPatternEntityEditor(EntityEditor):
|
||||
def getEntitiesFromContext(self):
|
||||
sDP = DamagePattern.getInstance()
|
||||
choices = sorted(sDP.getUserDamagePatternList(), key=lambda p: p.rawName)
|
||||
return [c for c in choices if c.rawName != "Selected Ammo"]
|
||||
choices = [c for c in choices if c.rawName != "Selected Ammo"]
|
||||
return choices
|
||||
|
||||
def DoNew(self, name):
|
||||
sDP = DamagePattern.getInstance()
|
||||
@@ -183,6 +184,10 @@ class DmgPatternEditor(AuxiliaryFrame):
|
||||
footerSizer.Add(btn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_RIGHT)
|
||||
btn.Bind(wx.EVT_BUTTON, getattr(self, "{}Patterns".format(name.lower())))
|
||||
|
||||
if not self.entityEditor.checkEntitiesExist():
|
||||
self.Close()
|
||||
return
|
||||
|
||||
self.Layout()
|
||||
bsize = self.GetBestSize()
|
||||
self.SetSize((-1, bsize.height))
|
||||
@@ -232,6 +237,11 @@ class DmgPatternEditor(AuxiliaryFrame):
|
||||
self.entityEditor.btnDelete.Enable()
|
||||
|
||||
def patternChanged(self, event=None):
|
||||
|
||||
if not self.entityEditor.checkEntitiesExist():
|
||||
self.Close()
|
||||
return
|
||||
|
||||
p = self.entityEditor.getActiveEntity()
|
||||
|
||||
if p is None:
|
||||
@@ -265,6 +275,8 @@ class DmgPatternEditor(AuxiliaryFrame):
|
||||
except ImportError as e:
|
||||
pyfalog.error(e)
|
||||
self.stNotice.SetLabel(str(e))
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as e:
|
||||
msg = "Could not import from clipboard: unknown errors"
|
||||
pyfalog.warning(msg)
|
||||
|
||||
@@ -168,10 +168,7 @@ class ItemView(d.Display):
|
||||
|
||||
def __init__(self, parent):
|
||||
d.Display.__init__(self, parent)
|
||||
sMkt = Market.getInstance()
|
||||
|
||||
self.things = sMkt.getItemsWithOverrides()
|
||||
self.items = self.things
|
||||
self.activeItems = []
|
||||
|
||||
self.searchBox = parent.Parent.Parent.searchBox
|
||||
# Bind search actions
|
||||
@@ -180,20 +177,16 @@ class ItemView(d.Display):
|
||||
self.searchBox.Bind(SBox.EVT_CANCEL_BTN, self.clearSearch)
|
||||
self.searchBox.Bind(SBox.EVT_TEXT, self.scheduleSearch)
|
||||
|
||||
self.update(self.items)
|
||||
self.update(Market.getInstance().getItemsWithOverrides())
|
||||
|
||||
def clearSearch(self, event=None):
|
||||
if event:
|
||||
self.searchBox.Clear()
|
||||
self.items = self.things
|
||||
self.update(self.items)
|
||||
self.update(Market.getInstance().getItemsWithOverrides())
|
||||
|
||||
def updateItems(self, updateDisplay=False):
|
||||
sMkt = Market.getInstance()
|
||||
self.things = sMkt.getItemsWithOverrides()
|
||||
self.items = self.things
|
||||
if updateDisplay:
|
||||
self.update(self.things)
|
||||
self.update(Market.getInstance().getItemsWithOverrides())
|
||||
|
||||
def scheduleSearch(self, event=None):
|
||||
sMkt = Market.getInstance()
|
||||
@@ -206,12 +199,40 @@ class ItemView(d.Display):
|
||||
self.clearSearch()
|
||||
return
|
||||
|
||||
sMkt.searchItems(search, self.populateSearch, False)
|
||||
sMkt.searchItems(search, self.populateSearch, 'everything')
|
||||
|
||||
def itemSort(self, item):
|
||||
sMkt = Market.getInstance()
|
||||
isFittable = item.group.name in sMkt.FIT_GROUPS or item.category.name in sMkt.FIT_CATEGORIES
|
||||
catname = sMkt.getCategoryByItem(item).name
|
||||
try:
|
||||
mktgrpid = sMkt.getMarketGroupByItem(item).ID
|
||||
except AttributeError:
|
||||
mktgrpid = -1
|
||||
pyfalog.warning("unable to find market group for {}".format(item.name))
|
||||
parentname = sMkt.getParentItemByItem(item).name
|
||||
# Get position of market group
|
||||
metagrpid = sMkt.getMetaGroupIdByItem(item)
|
||||
metatab = sMkt.META_MAP_REVERSE_INDICES.get(metagrpid)
|
||||
metalvl = item.metaLevel or 0
|
||||
|
||||
return not isFittable, catname, mktgrpid, parentname, metatab, metalvl, item.name
|
||||
|
||||
def populateSearch(self, items):
|
||||
self.items = list(items)
|
||||
self.update(items)
|
||||
|
||||
def populate(self, items):
|
||||
if len(items) > 0:
|
||||
self.unselectAll()
|
||||
items.sort(key=self.itemSort)
|
||||
self.activeItems = items
|
||||
d.Display.populate(self, items)
|
||||
|
||||
def refresh(self, items):
|
||||
if len(items) > 1:
|
||||
items.sort(key=self.itemSort)
|
||||
d.Display.refresh(self, items)
|
||||
|
||||
|
||||
class AttributeGrid(wxpg.PropertyGrid):
|
||||
def __init__(self, parent):
|
||||
@@ -236,7 +257,7 @@ class AttributeGrid(wxpg.PropertyGrid):
|
||||
self.Clear()
|
||||
self.btn.Enable(True)
|
||||
sel = event.EventObject.GetFirstSelected()
|
||||
self.item = item = self.itemView.items[sel]
|
||||
self.item = item = self.itemView.activeItems[sel]
|
||||
|
||||
for key in sorted(item.attributes.keys()):
|
||||
override = item.overrides.get(key, None)
|
||||
|
||||
@@ -211,6 +211,8 @@ class ImplantSetEditor(AuxiliaryFrame):
|
||||
except ImportError as e:
|
||||
pyfalog.error(e)
|
||||
self.stNotice.SetLabel(str(e))
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as e:
|
||||
pyfalog.error(e)
|
||||
self.stNotice.SetLabel("Could not import from clipboard: unknown errors")
|
||||
|
||||
@@ -25,12 +25,12 @@ from collections import OrderedDict
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import gui.mainFrame
|
||||
import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from gui.auxFrame import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.builtinViews.entityEditor import EntityEditor, BaseValidator
|
||||
from gui.utils.clipboard import toClipboard, fromClipboard
|
||||
from gui.builtinViews.entityEditor import BaseValidator, EntityEditor
|
||||
from gui.utils.clipboard import fromClipboard, toClipboard
|
||||
from gui.utils.inputs import FloatBox, InputValidator, strToFloat
|
||||
from service.fit import Fit
|
||||
from service.targetProfile import TargetProfile
|
||||
@@ -352,6 +352,8 @@ class TargetProfileEditor(AuxiliaryFrame):
|
||||
except ImportError as e:
|
||||
pyfalog.error(e)
|
||||
self.stNotice.SetLabel(str(e))
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as e:
|
||||
msg = "Could not import from clipboard:"
|
||||
pyfalog.warning(msg)
|
||||
|
||||
@@ -70,6 +70,8 @@ class exportHtmlThread(threading.Thread):
|
||||
except IOError as ex:
|
||||
pyfalog.warning("Failed to write to " + settings.getPath())
|
||||
pass
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except Exception as ex:
|
||||
pass
|
||||
|
||||
@@ -226,6 +228,8 @@ class exportHtmlThread(threading.Thread):
|
||||
|
||||
HTMLfit += ' </ul>\n </li>\n'
|
||||
HTMLship += HTMLfit
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
pyfalog.warning("Failed to export line")
|
||||
continue
|
||||
@@ -281,6 +285,8 @@ class exportHtmlThread(threading.Thread):
|
||||
HTML += '<a class="outOfGameBrowserLink" target="_blank" href="' + dnaUrl + dnaFit + '">' \
|
||||
+ ship.name + ': ' + \
|
||||
fit[1] + '</a><br> \n'
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
raise
|
||||
except:
|
||||
pyfalog.error("Failed to export line")
|
||||
continue
|
||||
|
||||
|
Before Width: | Height: | Size: 926 B After Width: | Height: | Size: 590 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 825 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 779 B |
|
Before Width: | Height: | Size: 824 B After Width: | Height: | Size: 585 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 913 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 778 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 732 B |
|
Before Width: | Height: | Size: 779 B After Width: | Height: | Size: 449 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 852 B |
|
Before Width: | Height: | Size: 740 B After Width: | Height: | Size: 438 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 897 B After Width: | Height: | Size: 693 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 137 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 138 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 138 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 142 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 142 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 141 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 141 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 142 B |
|
Before Width: | Height: | Size: 870 B After Width: | Height: | Size: 577 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 609 B After Width: | Height: | Size: 305 B |
|
Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 153 B |
|
Before Width: | Height: | Size: 325 B After Width: | Height: | Size: 113 B |
|
Before Width: | Height: | Size: 253 B After Width: | Height: | Size: 72 B |
|
Before Width: | Height: | Size: 316 B After Width: | Height: | Size: 109 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 936 B After Width: | Height: | Size: 669 B |
|
Before Width: | Height: | Size: 385 B After Width: | Height: | Size: 172 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 810 B After Width: | Height: | Size: 561 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1023 B |
|
Before Width: | Height: | Size: 926 B After Width: | Height: | Size: 633 B |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.2 KiB |