54 Commits

Author SHA1 Message Date
dependabot[bot]
1ad1f536de Bump urllib3 from 2.1.0 to 2.2.2 (#3)
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.1.0 to 2.2.2.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.1.0...2.2.2)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-19 01:35:25 +07:00
89f56be8b2 Proper variable names
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2024-06-19 01:30:33 +07:00
2b14be3832 Update README.md
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2024-06-17 19:14:03 +07:00
6330a0dfa8 Update
* Implemented show_progress_bar and update_progress_bar to interact with progress bars
* Added 3 progress bars to second window
* Imports little optimization

Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2024-06-17 08:26:19 +07:00
e9eef9f785 Fix research all dealers and agencies
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2024-05-24 20:30:08 +07:00
dependabot[bot]
f989c54664 --- (#2)
updated-dependencies:
- dependency-name: requests
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-21 17:36:44 +07:00
2d40c51f9c Update statics.py
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2024-05-13 19:29:21 +07:00
dependabot[bot]
9223095fe7 Bump idna from 3.6 to 3.7 (#1)
Bumps [idna](https://github.com/kjd/idna) from 3.6 to 3.7.
- [Release notes](https://github.com/kjd/idna/releases)
- [Changelog](https://github.com/kjd/idna/blob/master/HISTORY.rst)
- [Commits](https://github.com/kjd/idna/compare/v3.6...v3.7)

---
updated-dependencies:
- dependency-name: idna
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-13 19:23:06 +07:00
b9607db785 Update
* moved call check_remote_hashes into module_parsing

Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2024-05-12 18:00:36 +07:00
bafcb26fbe Update
* added progress dialog when download configs
* updated requirements (again)
* updated .gitignore
* updated second window flags
* warning fixes

Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2024-05-08 23:01:38 +07:00
b8cc20a184 Update
* small README update
* change exec() to exec_()
* added config parsing when app starting up
* setup.py fixes (for cx_Freeze build)
* updated requirements

Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2024-05-08 08:46:59 +07:00
dd238a0ae1 Update DLC_TABLE.md
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2024-02-08 16:07:30 +07:00
1afd4b6079 Update README.md
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2024-01-13 23:53:36 +07:00
dbcec7a6ed Update module_main/script.py
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2024-01-13 23:53:08 +07:00
70fceee6a2 Update requirements.txt
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-12-29 13:45:54 +07:00
242de815da Update DLC_TABLE.md
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-12-22 22:11:46 +07:00
c4cf9491d6 Update configs
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-12-01 21:44:59 +07:00
944c79dac0 Update DLC_TABLE.md
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-12-01 21:33:54 +07:00
33c21c4043 Update build.spec
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-11-12 13:40:30 +07:00
54331abf5a Use CDLL instead of WinDLL to load decrypt library
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-11-12 13:13:46 +07:00
aa071c7ea5 Update DLC_TABLE.md
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-11-02 18:18:12 +07:00
375e66e989 Update README.md
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-27 21:09:46 +07:00
59d4f89a96 Update README.md
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-27 21:08:50 +07:00
d2d814c870 Update README.md
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-27 21:07:11 +07:00
befed61b0c Added table with DLC info
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-27 20:59:28 +07:00
ef36387e05 Update requirements.txt
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-25 23:08:21 +07:00
da25c7bbc4 Update setup.py
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-25 23:05:33 +07:00
e21266970e Remove unused module_choice
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-23 15:20:13 +07:00
a2d4f84877 Automatically check configurations instead of user selection
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-23 14:58:39 +07:00
e7e4939882 Remove unused dlls
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-23 00:06:12 +07:00
66a571309d Particular revert "Update module_parsing"
This reverts commit 78141ae9aa.

Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-22 22:38:22 +07:00
7991cde695 Update setup.py
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-21 21:22:29 +07:00
b3d5776a3b Update module_second
* Fixed adding garage by name
* Make fill_list staticmethod
* Removed comments

Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-21 21:22:25 +07:00
b082e6ca3f Update module_main
* Fixed get_file_data
* Removed try-catch in recover_backup

Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-21 21:22:22 +07:00
dab9dc0467 Update module_choice
* Removed comments

Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-21 21:22:17 +07:00
8932327b5c Update utils
* Removed try-catch in generate_md5

Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-10-21 21:22:10 +07:00
994d6e4b13 Update module_second
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-02-12 13:14:45 +07:00
9c90daf8d5 Update module_choice
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-02-12 13:14:32 +07:00
78141ae9aa Update module_parsing
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-02-12 13:14:12 +07:00
8888a80b0c Update module_main
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2023-02-12 13:13:21 +07:00
bcb5cd03e6 [ATS] Added new DLC ("Texas")
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2022-12-15 17:42:21 +07:00
a7e5e47cb0 Update decrypt utility to latest avaliable version
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2022-08-09 15:03:44 +07:00
e6ef2bd50f Update .gitignore
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2022-08-08 14:43:38 +07:00
1f5c867444 [ATS] Added new DLC "Montana"
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2022-08-08 14:43:06 +07:00
f8ed7ec27f Update .gitignore, add requirements.txt
Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
2022-06-08 19:47:21 +07:00
fa552aa424 Update README.md
Signed-off-by: JDM170 <30170278+JDM170@users.noreply.github.com>
2021-12-08 00:41:23 +07:00
f1934d8d61 [ATS] Update configs
* Updated old DLC's ("Utah", "Idaho", "Colorado")
* Added new DLC ("Wyoming")

Signed-off-by: JDM170 <30170278+JDM170@users.noreply.github.com>
2021-09-18 19:12:56 +07:00
d5a9fe14a3 [ETS2] Update configs
* Updated old DLC's ("Vive la France", "Italia")
* Added new DLC ("Iberia")

Signed-off-by: JDM170 <30170278+JDM170@users.noreply.github.com>
2021-04-14 23:21:05 +07:00
69b815e917 Sort folders by renaming, some code changes
Signed-off-by: JDM170 <30170278+JDM170@users.noreply.github.com>
2020-12-16 22:15:34 +07:00
3dd855ff38 Added ATS DLC 'Colorado'
Signed-off-by: JDM170 <30170278+JDM170@users.noreply.github.com>
2020-12-16 22:15:34 +07:00
28a54d14f0 Added simple config editor
Signed-off-by: JDM170 <30170278+JDM170@users.noreply.github.com>
2020-08-22 10:26:50 +07:00
34f38b5a59 Update
* Updated build.spec for PyInstaller build
* Some code and typo fixes

Signed-off-by: JDM170 <30170278+JDM170@users.noreply.github.com>
2020-08-22 10:25:34 +07:00
33ce4d1148 Typo fixes
Signed-off-by: JDM170 <30170278+JDM170@users.noreply.github.com>
2020-08-05 18:46:02 +07:00
4dcfe37c5b Added version.cfg
Signed-off-by: JDM170 <30170278+JDM170@users.noreply.github.com>
2020-08-02 17:54:16 +07:00
53 changed files with 1546 additions and 1141 deletions

32
.gitignore vendored
View File

@@ -1,19 +1,27 @@
## Ignoring PyCharm settings
## Ignore PyCharm settings
/.idea
## Ignoring Python complied files
/__pycache__
/parsing/__pycache__
/choice/__pycache__
/main/__pycache__
/second/__pycache__
/choice/form.py
/main/form.py
/second/form.py
## Ignore virtual enviroment
/venv
## Ignoring build from cx_Freeze
## Ignore Python complied files
*__pycache__
## Ignore ui -> py transform
*/form.py
## Ignore UPX
/upx
## Ignore build from cx_Freeze
/prog_build
## Ignoring build files from PyInstaller
## Ignore build files from PyInstaller
/build
/dist
## Ignore .bak files
*.bak
## Ignore created 'update.cfg' file
update.cfg

35
DLC_TABLE.md Normal file
View File

@@ -0,0 +1,35 @@
# American Truck Simulator DLC table
| DLC name | Config name | File name (.scs) |
| --- | --- | --- |
| Arizona | arizona | dlc_arizona |
| New Mexico | new_mexico | dlc_nm |
| Oregon | oregon | dlc_or |
| Washington | washington | dlc_wa |
| Utah | utah | dlc_ut |
| Idaho | idaho | dlc_id |
| Colorado | colorado | dlc_co |
| Wyoming | wyoming | dlc_wy |
| Montana | montana | dlc_mt |
| Texas | texas | dlc_tx |
| Oklahoma | oklahoma | dlc_ok |
| Kansas | kansas | dlc_ks |
| Nebraska (not released) | nebraska | ? |
| Arkansas (not released) | arkansas | ? |
| Missouri (not released) | missouri | ? |
# Euro Truck Simulator 2 DLC table
| DLC name | Config name | File name (.scs) |
| --- | --- | --- |
| Going East | going_east | dlc_east |
| Scandinavia | scandinavia | dlc_north |
| Vive la France | france | dlc_fr |
| Italia | italy | dlc_it |
| Beyond the Baltic Sea | baltic_sea | dlc_balt |
| Road to the Black Sea | black_sea | dlc_balkan_e |
| Iberia | iberia | dlc_iberia |
| Heart of Russia (not released) | mother_russia | ? |
| West Balkans | west_balkans | dlc_balkan_w |
| Greece (not released) | greece | ? |
| Nordic Horizons (not released) | nordic_horizons | ? |

View File

@@ -2,27 +2,26 @@
* Author of original "SaveWizard" script: DrEGZo
* Original script is taken from here: <https://forum.truckersmp.com/index.php?/topic/55773-savewizard/> (access to the topic has been closed)
* Utility to decrypt file: <https://github.com/ncs-sniper/SII_Decrypt/> (repo has been removed)
* Utility to decrypt file: <https://github.com/TheLazyTomcat/SII_Decrypt>
***
Features:
1. Decrypt file, if save file crypted
2. Check for DLC to the save file
2. Check for DLC to the save file (available DLC listed at [DLC_TABLE.md](https://github.com/JDM170/SaveWizard/blob/configs/DLC_TABLE.md))
3. Edit money, experience and loan limit
4. Edit skills
5. Unlock garages, visit cities, unlock dealers and agencies
**This functionality of the program isn't final!**
5. Visit cities, unlock garages, dealers and agencies
***
Requirments:
* Python 3.7.7
* PyQt5 5.15.0
* requests 2.24.0
* cx_Freeze 6.2
To build project You need Python 3.10.7 and installed requirements from [requirements.txt](https://github.com/JDM170/SaveWizard/blob/dev/requirements.txt)
Command to convert .ui to .py: ```pyuic5 -x input.ui -o output.py```
Commands to build project:
- cx_Freeze: ```python setup.py build```
- PyInstaller: ```pyinstaller build.spec --clean```
***
#### Since the program is in development, I won't give up help and guidance on my errors in the code.
#### If you've found a bug - please open an issue

BIN
SII_Decrypt.dll Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -1,38 +1,59 @@
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
app = Analysis(
['init_main_program.py'],
pathex=['.'],
datas=[
('SII_Decrypt.dll', '.'),
('configs/ats', 'configs/ats'),
('configs/ets2', 'configs/ets2')
]
)
cfg = Analysis(
['init_config_editor.py'],
pathex=['.']
)
a = Analysis(['__init__.py'],
pathex=['.'],
binaries=[],
datas=[
('ats_configs', 'ats_configs'),
('ets2_configs', 'ets2_configs')
],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='SaveWizard',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='build')
MERGE(
(app, 'SaveWizard', 'SaveWizard'),
(cfg, 'SaveWizard_Config_Editor', 'SaveWizard_Config_Editor')
)
app_pyz = PYZ(app.pure, app.zipped_data)
cfg_pyz = PYZ(cfg.pure, cfg.zipped_data)
app_exe = EXE(
app_pyz,
app.scripts,
[],
exclude_binaries=True,
name='SaveWizard',
debug=False,
bootloader_ignore_signals=False,
strip=False,
console=False
)
cfg_exe = EXE(
cfg_pyz,
cfg.scripts,
[],
exclude_binaries=True,
name='SaveWizard_Config_Editor',
debug=False,
bootloader_ignore_signals=False,
strip=False,
console=False
)
coll = COLLECT(
app_exe,
app.binaries,
app.zipfiles,
app.datas,
cfg_exe,
cfg.binaries,
cfg.zipfiles,
cfg.datas,
strip=False,
name='app_build'
)

View File

@@ -1 +0,0 @@
# initialize module 'choice'

View File

@@ -1,106 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Choice</class>
<widget class="QDialog" name="Choice">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>490</width>
<height>130</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>490</width>
<height>130</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>490</width>
<height>130</height>
</size>
</property>
<property name="windowTitle">
<string>Select game</string>
</property>
<widget class="QWidget" name="gridLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>471</width>
<height>111</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QPushButton" name="ets2_button">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>ETS2</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="ats_button">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>ATS</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>18</pointsize>
</font>
</property>
<property name="text">
<string>Select the configs you want to use:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>DON'T USE CONFIGS FROM ANOTHER GAME INTENTIONALLY,
YOU CAN DAMAGE THE GAME'S SAVE.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<tabstops>
<tabstop>ats_button</tabstop>
<tabstop>ets2_button</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@@ -1,58 +0,0 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QDialog, QMessageBox
from ast import literal_eval
from .form import Ui_Choice
from main.script import MainWindow
from parsing.script import check_remote_hashes, update_configs
from util import update_config_name
class ChoiceWindow(QDialog, Ui_Choice):
def __init__(self, parent=None):
# Setup UI
QDialog.__init__(self, parent, flags=Qt.Window)
Ui_Choice.__init__(self)
self.ui = Ui_Choice()
self.ui.setupUi(self)
self.ui.ats_button.clicked.connect(self.button_clicked)
self.ui.ets2_button.clicked.connect(self.button_clicked)
remember_data = {"answer_updates": True, "update_on_start": False}
try:
with open(update_config_name) as f:
remember_data = literal_eval(f.read())
except FileNotFoundError:
with open(update_config_name, "w") as f:
f.write(str(remember_data))
upd_list = check_remote_hashes()
if upd_list and len(upd_list) > 0:
answer = remember_data.get("answer_updates")
if answer:
box = QMessageBox(QMessageBox.Information, "Info",
"Some configs get updated, do you want update your local configs?")
box.addButton("Yes", QMessageBox.YesRole) # 0
box.addButton("Yes, remember that", QMessageBox.YesRole) # 1
box.addButton("No", QMessageBox.NoRole) # 2
box.addButton("No, remember that", QMessageBox.NoRole) # 3
update_configs(box.exec(), upd_list)
return
upd_on_start = remember_data.get("update_on_start")
if upd_on_start:
update_configs(1, upd_list)
def button_clicked(self):
sender = self.sender()
if sender == self.ui.ats_button:
selected = "ats"
elif sender == self.ui.ets2_button:
selected = "ets2"
else:
return
self.close()
win = MainWindow(selected)
win.exec()

View File

@@ -1 +0,0 @@
python setup.py build

View File

@@ -1 +0,0 @@
pyinstaller build.spec

View File

@@ -1,27 +1,21 @@
{
"arizona" : [
"phoenix",
"sierra_vista",
"tucson"
],
"base" : [
"bakersfield",
"carson_city",
"fresno",
"las_vegas",
"los_angeles",
"oxnard",
"redding",
"san_diego",
"san_rafael",
"santa_cruz",
"stockton",
"carson_city",
"las_vegas"
"stockton"
],
"idaho" : [
"boise",
"coeur_dalene",
"idaho_falls",
"twin_falls"
"arizona" : [
"phoenix",
"sierra_vista",
"tucson"
],
"new_mexico" : [
"carlsbad_nm",
@@ -35,16 +29,60 @@
"ontario",
"salem"
],
"utah" : [
"moab",
"salt_lake_city",
"st_george"
],
"washington" : [
"bellingham",
"olympia",
"seattle",
"wenatchee",
"yakima"
],
"utah" : [
"moab",
"price",
"salt_lake",
"st_george"
],
"idaho" : [
"boise",
"coeur_dalene",
"idaho_falls",
"twin_falls"
],
"colorado" : [
"alamosa",
"denver",
"fort_collins"
],
"wyoming" : [
"casper",
"cheyenne",
"rock_springs",
"sheridan"
],
"montana" : [
"great_falls",
"havre",
"helena",
"kalispell"
],
"texas" : [
"corpus_chris",
"dallas",
"el_paso",
"houston",
"huntsville",
"laredo",
"san_antonio"
],
"oklahoma" : [
"ardmore",
"enid"
],
"kansas" : [
"hays",
"kansas_ci_ks",
"salina_ks",
"topeka",
"wichita"
]
}

View File

@@ -1,23 +1,24 @@
{
"base" : [
"bakersfield",
"elko",
"las_vegas",
"los_angeles",
"oxnard",
"redding",
"reno",
"sacramento",
"san_diego",
"san_francisc",
"santa_cruz",
"stockton"
],
"arizona" : [
"flagstaff",
"phoenix",
"tucson",
"yuma"
],
"base" : [
"bakersfield",
"los_angeles",
"sacramento",
"santa_cruz",
"san_diego",
"san_francisco"
],
"idaho" : [
"boise",
"idaho_falls",
"twin_falls"
],
"new_mexico" : [
"alamogordo",
"albuquerque",
@@ -31,19 +32,80 @@
"portland",
"salem"
],
"utah" : [
"ogden",
"price",
"provo",
"salina",
"salt_lake_city",
"vernal"
],
"washington" : [
"bellingham",
"seattle",
"spokane",
"tacoma",
"yakima"
],
"utah" : [
"ogden",
"price",
"provo",
"salina",
"salt_lake",
"st_george",
"vernal"
],
"idaho" : [
"boise",
"idaho_falls",
"lewiston",
"twin_falls"
],
"colorado" : [
"alamosa",
"colorado_spr",
"denver",
"fort_collins",
"grand_juncti",
"montrose",
"pueblo"
],
"wyoming" : [
"casper",
"cheyenne",
"gillette",
"rock_springs"
],
"montana" : [
"billings",
"great_falls",
"helena",
"kalispell",
"missoula"
],
"texas" : [
"abilene",
"amarillo",
"austin",
"corpus_chris",
"dallas",
"el_paso",
"fort_worth",
"houston",
"laredo",
"longview_tx",
"lubbock",
"mcallen",
"odessa",
"san_angelo",
"san_antonio",
"waco"
],
"oklahoma" : [
"ardmore",
"enid",
"oklahoma_cit"
],
"kansas" : [
"dodge_city",
"emporia",
"garden_city",
"hays",
"kansas_ci_ks",
"salina_ks",
"wichita"
]
}

View File

@@ -1,8 +1,14 @@
{
"arizona" : "company.volatile.aport_phx.phoenix",
"idaho" : "company.volatile.du_farm.nampa",
"new_mexico" : "company.volatile.aport_abq.albuquerque",
"oregon" : "company.volatile.aport_pcc.portland",
"utah" : "company.volatile.gal_oil_sit.price",
"washington" : "company.volatile.port_sea.seattle"
"washington" : "company.volatile.port_sea.seattle",
"utah" : "company.volatile.cm_min_qryp.moab",
"idaho" : "company.volatile.du_farm.nampa",
"colorado" : "company.volatile.aport_den.denver",
"wyoming" : "company.volatile.aml_rail_str.cheyenne",
"montana" : "company.volatile.aport_gtf.great_falls",
"texas" : "company.volatile.aport_dfw.fort_worth",
"oklahoma" : "company.volatile.aport_tul.tulsa",
"kansas" : "company.volatile.ai_car_whs.junction_cty"
}

View File

@@ -1,20 +1,4 @@
{
"balticsea" : [
"daugavpils",
"helsinki",
"kaliningrad",
"kaunas",
"klaipeda",
"kouvola",
"lahti",
"parnu",
"pori",
"pskov",
"riga",
"tallinn",
"turku",
"vilnius"
],
"base" : [
"aberdeen",
"berlin",
@@ -32,7 +16,7 @@
"frankfurt",
"glasgow",
"graz",
"grohningen",
"groningen",
"hamburg",
"hannover",
"innsbruck",
@@ -62,46 +46,16 @@
"stuttgart",
"swansea",
"szczecin",
"travemunde",
"wien",
"zurich"
],
"blacksea" : [
"bucuresti",
"cluj_napoca",
"iasi",
"istanbul",
"plovdiv",
"sofia"
],
"east" : [
"budapest",
"gdansk",
"krakow",
"szeged",
"warszava"
],
"france" : [
"bordeaux",
"clermont",
"geneve",
"larochelle",
"lyon",
"marseille",
"metz",
"paris",
"reims",
"rennes",
"toulouse"
],
"italy" : [
"bologna",
"catania",
"milano",
"napoli",
"pescara",
"roma",
"taranto",
"venezia"
"warszawa"
],
"scandinavia" : [
"aalborg",
@@ -113,5 +67,73 @@
"oslo",
"stavanger",
"stockholm"
],
"france" : [
"ajaccio",
"bordeaux",
"clermont",
"geneve",
"larochelle",
"lyon",
"marseille",
"metz",
"paris",
"rennes",
"toulouse"
],
"italy" : [
"bologna",
"cagliari",
"catania",
"milano",
"napoli",
"pescara",
"roma",
"taranto",
"venezia"
],
"baltic_sea" : [
"daugavpils",
"helsinki",
"kaliningrad",
"kaunas",
"klaipeda",
"kouvola",
"lahti",
"parnu",
"pori",
"pskov",
"riga",
"tallinn",
"turku",
"vilnius"
],
"black_sea" : [
"bucuresti",
"cluj_napoca",
"iasi",
"istanbul",
"plovdiv",
"sofia"
],
"iberia" : [
"bilbao",
"leon",
"lisboa",
"madrid",
"malaga",
"murcia",
"porto",
"valencia",
"zaragoza"
],
"west_balkans" : [
"beograd",
"ljubljana",
"maribor",
"sarajevo",
"skopje",
"tirana",
"zagreb"
]
}

View File

@@ -1,17 +1,4 @@
{
"balticsea" : [
"helsinki",
"kaliningrad",
"kaunas",
"klaipeda",
"lahti",
"petersburg",
"riga",
"tallinn",
"tartu",
"turku",
"vilnius"
],
"base" : [
"aberdeen",
"amsterdam",
@@ -24,7 +11,6 @@
"calais",
"cardiff",
"dortmund",
"dortmund",
"dresden",
"dusseldorf",
"edinburgh",
@@ -56,20 +42,6 @@
"wroclaw",
"zurich"
],
"blacksea" : [
"brasov",
"bucuresti",
"cluj_napoca",
"constanta",
"edirne",
"galati",
"iasi",
"istanbul",
"pitesti",
"plovdiv",
"sofia",
"veliko_tarnovo"
],
"east" : [
"budapest",
"gdansk",
@@ -77,7 +49,18 @@
"szeged",
"warszawa"
],
"scandinavia" : [
"bergen",
"goteborg",
"kalmar",
"kobenhavn",
"linkoping",
"oslo",
"stockholm"
],
"france" : [
"ajaccio",
"bayonne",
"bordeaux",
"bourges",
"brest",
@@ -92,23 +75,75 @@
],
"italy" : [
"bologna",
"cagliari",
"catania",
"firenze",
"milano",
"napoli",
"palermo",
"roma",
"sassari",
"taranto",
"torino",
"verona"
],
"scandinavia" : [
"bergen",
"goteborg",
"kalmar",
"kobenhavn",
"linkoping",
"oslo",
"stockholm"
"baltic_sea" : [
"helsinki",
"kaliningrad",
"kaunas",
"klaipeda",
"lahti",
"petersburg",
"riga",
"tallinn",
"tartu",
"turku",
"vilnius"
],
"black_sea" : [
"brasov",
"bucuresti",
"cluj_napoca",
"constanta",
"edirne",
"galati",
"iasi",
"istanbul",
"pitesti",
"plovdiv",
"sofia",
"veliko_tarnovo"
],
"iberia" : [
"albacete",
"almeria",
"badajoz",
"barcelona",
"burgos",
"cordoba",
"gijon",
"leon",
"lisboa",
"madrid",
"malaga",
"porto",
"sevilla",
"valladolid",
"zaragoza"
],
"west_balkans" : [
"banja_luka",
"beograd",
"kragujevac",
"ljubljana",
"maribor",
"podgorica",
"pristina",
"rijeka",
"skopje",
"split",
"tirana",
"tuzla",
"zagreb"
]
}

View File

@@ -1,8 +1,10 @@
{
"balticsea" : "company.volatile.polarislines.tallinn",
"blacksea" : "company.volatile.bhv.galati",
"east" : "company.volatile.quarry.katowice",
"france" : "company.volatile.lisette_log.roscoff",
"italy" : "company.volatile.marina_it.ancona",
"scandinavia" : "company.volatile.sag_tre.oslo"
"scandinavia" : "company.volatile.sag_tre.oslo",
"france" : "company.volatile.batisse_base.calvi",
"italy" : "company.volatile.c_navale.ancona",
"baltic_sea" : "company.volatile.aerobalt.helsinki",
"black_sea" : "company.volatile.balkan_loco.craiova",
"iberia" : "company.volatile.tdc_auto.vigo",
"west_balkans" : "company.volatile.adrica.rijeka"
}

8
configs/version.cfg Normal file
View File

@@ -0,0 +1,8 @@
{
"ats_dlc": "96254fdb25d45d084b85b52a571f15db",
"ats_agencies": "7a1499478092ca45ed226bd8ca7d6867",
"ats_dealers": "78a88c9ce064276063f34eb4bc1cff88",
"ets2_dlc": "38a4fa4c9ec51a4cb4754b4bd315cd24",
"ets2_agencies": "155bfef072aedf17963a426e791d5b92",
"ets2_dealers": "7412c51266e3378828e5bdeca3fe8912"
}

View File

@@ -1,13 +0,0 @@
cls
@echo off
title Form converter
:SETUP
echo Enter form name to convert into .py (without .ui):
echo Type 'exit' to exit
set/p "name=> "
if %name%==exit goto EXIT
pyuic5 %name%.ui -o %name%.py
goto SETUP
:EXIT

View File

@@ -2,13 +2,6 @@
# -*- coding: utf-8 -*-
from json import decoder, load, dump
from os import replace
from os.path import splitext
from random import randint
class InvalidFileIO(Exception):
pass
class DataIO:
@@ -18,12 +11,6 @@ class DataIO:
data = load(f)
return data
@staticmethod
def _save_json(filename, data):
with open(filename, encoding="utf-8", mode="w") as f:
dump(data, f, indent=4, sort_keys=True, separators=(",", " : "))
return data
def is_valid_json(self, filename):
"""Verifies if json file exists / is readable"""
try:
@@ -40,15 +27,12 @@ class DataIO:
def save_json(self, filename, data):
"""Atomically saves json file"""
rnd = randint(1000, 9999)
path, ext = splitext(filename)
tmp_file = "{}-{}.tmp".format(path, rnd)
self._save_json(tmp_file, data)
with open(filename, encoding="utf-8", mode="w") as f:
dump(data, f, indent=4, separators=(",", " : "))
try:
self._read_json(tmp_file)
self._read_json(filename)
except decoder.JSONDecodeError:
return False
replace(tmp_file, filename)
return True

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

12
init_config_editor.py Normal file
View File

@@ -0,0 +1,12 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from sys import argv, exit
from PyQt5.QtWidgets import QApplication
from module_config_editor.script import EditorWindow
if __name__ == '__main__':
app = QApplication(argv)
win = EditorWindow()
win.show()
exit(app.exec_())

View File

@@ -3,10 +3,10 @@
from sys import argv, exit
from PyQt5.QtWidgets import QApplication
from choice.script import ChoiceWindow
from module_main.script import MainWindow
if __name__ == '__main__':
app = QApplication(argv)
win = ChoiceWindow()
win = MainWindow()
win.show()
exit(app.exec())
exit(app.exec_())

View File

@@ -0,0 +1 @@
# initializing module 'config_editor'

View File

@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<author>JDM170</author>
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>504</width>
<height>374</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>SaveWizard config editor</string>
</property>
<property name="dockOptions">
<set>QMainWindow::AllowTabbedDocks</set>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QTextEdit" name="textEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>501</width>
<height>351</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Verdana</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>504</width>
<height>21</height>
</rect>
</property>
<property name="defaultUp">
<bool>true</bool>
</property>
<property name="nativeMenuBar">
<bool>false</bool>
</property>
<widget class="QMenu" name="menuOptions">
<property name="title">
<string>Options</string>
</property>
<addaction name="actionOpen"/>
<addaction name="actionSave"/>
<addaction name="actionSave_As"/>
<addaction name="separator"/>
<addaction name="actionMD5"/>
<addaction name="separator"/>
<addaction name="actionCloseFile"/>
<addaction name="actionExit"/>
</widget>
<addaction name="menuOptions"/>
</widget>
<action name="actionOpen">
<property name="text">
<string>Open</string>
</property>
<property name="shortcut">
<string>Ctrl+O</string>
</property>
</action>
<action name="actionSave">
<property name="text">
<string>Save</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
<action name="actionSave_As">
<property name="text">
<string>Save As</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+S</string>
</property>
</action>
<action name="actionCloseFile">
<property name="text">
<string>Close file</string>
</property>
<property name="toolTip">
<string>Closing current file</string>
</property>
<property name="shortcut">
<string>Ctrl+W</string>
</property>
</action>
<action name="actionExit">
<property name="text">
<string>Exit</string>
</property>
</action>
<action name="actionMD5">
<property name="text">
<string>Copy MD5</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,111 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PyQt5.QtGui import QResizeEvent, QCloseEvent, QClipboard
from PyQt5.QtWidgets import QMainWindow, QFileDialog, QMessageBox, QApplication
from ast import literal_eval
from .form import Ui_MainWindow
from dataIO import dataIO
from util import util
class EditorWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent, flags=Qt.Window)
Ui_MainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.file_path = ""
self.win_title = self.tr("{}".format(self.windowTitle()))
self.ui.textEdit.document().contentsChanged.connect(self.content_changed)
for action, method in {
self.ui.actionOpen: self.open_file,
self.ui.actionSave: self.save_file,
self.ui.actionSave_As: self.save_as,
self.ui.actionMD5: self.copy_hash,
self.ui.actionCloseFile: self.close_file,
self.ui.actionExit: self.exit
}.items():
action.triggered.connect(method)
def resizeEvent(self, event: QResizeEvent):
window = self.ui.centralwidget.geometry().getCoords()
edit = self.ui.textEdit.geometry().getCoords()
self.ui.textEdit.setGeometry(edit[0], edit[1],
window[2], window[3]-(self.ui.menubar.size().height()-1))
def closeEvent(self, event: QCloseEvent):
if self.maybe_save():
event.accept()
else:
event.ignore()
def content_changed(self):
self.setWindowModified(self.ui.textEdit.document().isModified())
def open_file(self):
file_path, file_name = QFileDialog.getOpenFileName(parent=self,
caption=self.tr("Choose config..."),
filter=self.tr("*.json"))
if file_path != "":
self.file_path = file_path
with open(file_path) as f:
self.ui.textEdit.setPlainText(f.read())
self.setWindowTitle(self.tr("[*]{} - {}".format(file_path, self.win_title)))
self.ui.textEdit.document().setModified(False)
self.setWindowModified(False)
def save_file(self):
if self.file_path != "":
data = literal_eval(self.ui.textEdit.toPlainText())
ret = dataIO.save_json(self.file_path, data)
if ret:
self.ui.textEdit.document().setModified(False)
self.setWindowModified(False)
return ret
def save_as(self):
file_path, file_name = QFileDialog.getSaveFileName(parent=self,
caption=self.tr("Select place to save file"),
filter=self.tr("*.json"))
file_data = literal_eval(self.ui.textEdit.toPlainText())
ret = dataIO.save_json(file_path, file_data)
if ret:
self.file_path = file_path
self.setWindowTitle(self.tr("[*]{} - {}".format(file_path, self.win_title)))
self.ui.textEdit.document().setModified(False)
self.setWindowModified(False)
def copy_hash(self):
if self.maybe_save():
result = util.generate_md5(self.file_path)
clip = QApplication.clipboard()
QClipboard.setText(clip, result)
QMessageBox.information(self, "Information", "Hash successfully copied into your clipboard.")
def close_file(self):
if self.maybe_save():
self.setWindowTitle(self.win_title)
self.ui.textEdit.clear()
self.file_path = ""
def exit(self):
self.close()
def maybe_save(self):
if not self.ui.textEdit.document().isModified():
return True
box = QMessageBox.warning(self,
self.tr("SaveWizard config editor"),
self.tr("The document has been modified.\nDo you want to save your changes?"),
QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)
if box == QMessageBox.Save:
return self.save_file()
elif box == QMessageBox.Discard:
return True
elif box == QMessageBox.Cancel:
return False
return True

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<author>JDM170</author>
<class>MainWindow</class>
<widget class="QDialog" name="MainWindow">
<property name="geometry">
@@ -7,19 +8,19 @@
<x>0</x>
<y>0</y>
<width>360</width>
<height>350</height>
<height>400</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>360</width>
<height>350</height>
<height>400</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>360</width>
<height>350</height>
<height>400</height>
</size>
</property>
<property name="font">
@@ -37,21 +38,11 @@
<x>10</x>
<y>50</y>
<width>341</width>
<height>81</height>
<height>104</height>
</rect>
</property>
<layout class="QGridLayout" name="basic_inf_layout">
<item row="0" column="1">
<widget class="QLineEdit" name="money_edit">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
<item row="0" column="2">
<item row="1" column="2">
<widget class="QCheckBox" name="money_dont_change">
<property name="font">
<font>
@@ -64,7 +55,7 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item row="2" column="0">
<widget class="QLabel" name="xp_label">
<property name="font">
<font>
@@ -77,7 +68,7 @@
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QLineEdit" name="xp_edit">
<property name="font">
<font>
@@ -87,7 +78,17 @@
</property>
</widget>
</item>
<item row="1" column="2">
<item row="1" column="1">
<widget class="QLineEdit" name="money_edit">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QCheckBox" name="xp_dont_change">
<property name="font">
<font>
@@ -100,20 +101,7 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="loan_limit_label">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>Loan limit:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="QLineEdit" name="loan_limit_edit">
<property name="font">
<font>
@@ -123,7 +111,7 @@
</property>
</widget>
</item>
<item row="2" column="2">
<item row="3" column="2">
<widget class="QCheckBox" name="loan_limit_dont_change">
<property name="font">
<font>
@@ -136,7 +124,7 @@
</property>
</widget>
</item>
<item row="0" column="0">
<item row="1" column="0">
<widget class="QLabel" name="money_label">
<property name="font">
<font>
@@ -149,6 +137,34 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="loan_limit_label">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>Loan limit:</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="basic_inf_label">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>Basic info</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QPushButton" name="path_button">
@@ -176,16 +192,16 @@
</property>
<property name="geometry">
<rect>
<x>10</x>
<y>310</y>
<width>141</width>
<x>130</x>
<y>360</y>
<width>111</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>12</pointsize>
<pointsize>11</pointsize>
</font>
</property>
<property name="text">
@@ -193,12 +209,15 @@
</property>
</widget>
<widget class="QCheckBox" name="dont_change_all_inf">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>80</x>
<y>350</y>
<y>400</y>
<width>211</width>
<height>31</height>
<height>21</height>
</rect>
</property>
<property name="font">
@@ -210,97 +229,21 @@
<property name="text">
<string>Don't save all changes in this form</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
<widget class="QWidget" name="gridLayoutWidget_3">
<property name="geometry">
<rect>
<x>10</x>
<y>140</y>
<y>160</y>
<width>341</width>
<height>161</height>
<height>191</height>
</rect>
</property>
<layout class="QGridLayout" name="skills_layout">
<item row="1" column="1">
<widget class="QLineEdit" name="long_distance_edit">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="urgent_delivery_label">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>13</pointsize>
</font>
</property>
<property name="text">
<string>Urgent delivery:</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QCheckBox" name="ecodriving_dont_change">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Don't change</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="adr_edit">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="urgent_delivery_edit">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QCheckBox" name="fragile_cargo_dont_change">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Don't change</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="ecodriving_edit">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QCheckBox" name="high_value_cargo_dont_change">
<property name="font">
<font>
@@ -313,30 +256,7 @@
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="fragile_cargo_edit">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="adr_dont_change">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Don't change</string>
</property>
</widget>
</item>
<item row="1" column="2">
<item row="2" column="2">
<widget class="QCheckBox" name="long_distance_dont_change">
<property name="font">
<font>
@@ -349,8 +269,8 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="high_value_cargo_edit">
<item row="6" column="1">
<widget class="QLineEdit" name="ecodriving_edit">
<property name="font">
<font>
<family>Times New Roman</family>
@@ -359,33 +279,30 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="high_value_cargo_label">
<item row="1" column="2">
<widget class="QCheckBox" name="adr_dont_change">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>13</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>High value cargo:</string>
<string>Don't change</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="fragile_cargo_label">
<item row="4" column="1">
<widget class="QLineEdit" name="fragile_cargo_edit">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>13</pointsize>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Fragile cargo:</string>
</property>
</widget>
</item>
<item row="5" column="0">
<item row="6" column="0">
<widget class="QLabel" name="ecodriving_label">
<property name="font">
<font>
@@ -398,7 +315,30 @@
</property>
</widget>
</item>
<item row="4" column="2">
<item row="3" column="0">
<widget class="QLabel" name="high_value_cargo_label">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>13</pointsize>
</font>
</property>
<property name="text">
<string>High value cargo:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="high_value_cargo_edit">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QCheckBox" name="urgent_delivery_dont_change">
<property name="font">
<font>
@@ -411,7 +351,20 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item row="4" column="0">
<widget class="QLabel" name="fragile_cargo_label">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>13</pointsize>
</font>
</property>
<property name="text">
<string>Fragile cargo:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="long_distance_label">
<property name="font">
<font>
@@ -424,7 +377,7 @@
</property>
</widget>
</item>
<item row="0" column="0">
<item row="1" column="0">
<widget class="QLabel" name="adr_label">
<property name="font">
<font>
@@ -437,6 +390,90 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="urgent_delivery_label">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>13</pointsize>
</font>
</property>
<property name="text">
<string>Urgent delivery:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="long_distance_edit">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="urgent_delivery_edit">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QCheckBox" name="fragile_cargo_dont_change">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Don't change</string>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QCheckBox" name="ecodriving_dont_change">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Don't change</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="adr_edit">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="skills_label">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>Skills</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QPushButton" name="apply">
@@ -445,16 +482,16 @@
</property>
<property name="geometry">
<rect>
<x>210</x>
<y>310</y>
<width>141</width>
<x>250</x>
<y>360</y>
<width>101</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>12</pointsize>
<pointsize>11</pointsize>
</font>
</property>
<property name="text">
@@ -467,49 +504,37 @@
</property>
<property name="geometry">
<rect>
<x>160</x>
<y>320</y>
<width>41</width>
<height>21</height>
<x>10</x>
<y>360</y>
<width>111</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
</font>
</property>
<property name="text">
<string>...</string>
<string>Unlock garages</string>
</property>
</widget>
<widget class="QLabel" name="chosen_cfgs">
<widget class="QCheckBox" name="updates_checkbox">
<property name="geometry">
<rect>
<x>210</x>
<x>180</x>
<y>10</y>
<width>141</width>
<width>181</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>Chosen configs:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<widget class="QPushButton" name="cfg_button">
<property name="geometry">
<rect>
<x>180</x>
<y>20</y>
<width>21</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>...</string>
<string>Check updates on startup</string>
</property>
</widget>
</widget>
<tabstops>
<tabstop>path_button</tabstop>
<tabstop>cfg_button</tabstop>
<tabstop>money_edit</tabstop>
<tabstop>money_dont_change</tabstop>
<tabstop>xp_edit</tabstop>
@@ -528,8 +553,8 @@
<tabstop>urgent_delivery_dont_change</tabstop>
<tabstop>ecodriving_edit</tabstop>
<tabstop>ecodriving_dont_change</tabstop>
<tabstop>backup</tabstop>
<tabstop>second_window</tabstop>
<tabstop>backup</tabstop>
<tabstop>apply</tabstop>
<tabstop>dont_change_all_inf</tabstop>
</tabstops>

View File

@@ -1,35 +1,49 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from os import system, remove
from PyQt5.QtCore import Qt, QRegExp
from ast import literal_eval
from ctypes import CDLL
from os import getcwd, remove
from PyQt5.QtCore import QRegExp
from PyQt5.QtGui import QRegExpValidator
from PyQt5.QtWidgets import QDialog, QFileDialog
from .form import Ui_MainWindow
from util import *
from dataIO import dataIO
from second.script import SecondWindow
from module_parsing.script import update_configs
from module_second.script import SecondWindow
from statics import update_config_name
from util import *
from .form import Ui_MainWindow
libDecrypt = CDLL("{}\\SII_Decrypt.dll".format(getcwd()))
class MainWindow(QDialog, Ui_MainWindow):
def __init__(self, selected_game, parent=None):
def __init__(self, parent=None):
# Setup UI
QDialog.__init__(self, parent, flags=Qt.Window)
Ui_MainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
update_cfg = {"update_on_start": False}
if isfile(update_config_name):
with open(update_config_name, "r") as f:
update_cfg = literal_eval(f.read())
update_bool = update_cfg.get("update_on_start")
if update_bool:
self.ui.updates_checkbox.setChecked(update_bool)
update_configs()
self.file_path = ""
self.old_file = ""
self.selected_game = selected_game
self.selected_game = ""
self.owns = {}
self.dlc = {}
# Editing label to show what configs chosen
self.chosen_cfg_text = self.ui.chosen_cfgs.text()
self.ui.chosen_cfgs.setText("{} {}".format(self.chosen_cfg_text, selected_game.upper()))
# Storing edits with his checkboxes and file-lines
self.basic_edits = {
self.ui.money_edit: [self.ui.money_dont_change, "money_account:"],
@@ -62,13 +76,12 @@ class MainWindow(QDialog, Ui_MainWindow):
# Connecting buttons
self.ui.path_button.clicked.connect(self.open_file_dialog)
self.ui.cfg_button.clicked.connect(self.change_configs)
self.ui.backup.clicked.connect(self.recover_backup)
self.ui.updates_checkbox.clicked.connect(self.update_on_startup)
self.ui.second_window.clicked.connect(self.open_second_win)
self.ui.backup.clicked.connect(self.recover_backup)
self.ui.apply.clicked.connect(self.apply_changes)
self.check_config()
self.clear_fields()
self.clear_form_data()
def text_edited(self):
sender = self.sender()
@@ -99,19 +112,20 @@ class MainWindow(QDialog, Ui_MainWindow):
cfg_path = "configs/{}/dlc.json".format(self.selected_game)
if dataIO.is_valid_json(cfg_path) is False:
self.owns = False
show_message(QMessageBox.Warning, "Warning", "'dlc.json' from '{}' not found, functionality "
"has been limited".format(self.selected_game))
QMessageBox.warning(self, "Warning", "'dlc.json' from '{}' have errors or not found, "
"functionality has been limited".format(self.selected_game))
else:
self.owns = {}
self.dlc = dataIO.load_json(cfg_path)
def clear_fields(self):
def clear_form_data(self):
self.file_path = ""
self.old_file = ""
set_lines([])
util.set_lines([])
if self.owns is not False:
self.owns = {}
self.selected_game = ""
self.owns = {}
self.dlc = {}
for key, value in self.basic_edits.items():
key.setText("")
@@ -127,39 +141,41 @@ class MainWindow(QDialog, Ui_MainWindow):
self.ui.backup.setEnabled(False)
self.ui.second_window.setEnabled(False)
def get_file_data(self, file):
try:
with open(file) as f:
self.old_file = f.read()
except UnicodeDecodeError:
try:
system("SII_Decrypt.exe --on_file -i \"{}\"".format(file))
with open(file) as f:
self.old_file = f.read()
show_message(QMessageBox.Information, "Success", "File successfully decrypted.")
except UnicodeDecodeError:
show_message(QMessageBox.Critical, "Error", "Error to decrypt and open file. Try again.")
def get_file_data(self, file_path):
bytes_file_path = file_path.replace("/", "\\").encode("utf-8")
if libDecrypt.GetFileFormat(bytes_file_path) == 2:
if libDecrypt.DecryptAndDecodeFile(bytes_file_path, bytes_file_path) != 0:
QMessageBox.critical(self, "Error", "Something went wrong with decrypting file. Try again.")
return
set_lines(self.old_file.split("\n"))
with open(file_path) as f:
self.old_file = f.read()
util.set_lines(self.old_file.split("\n"))
if util.search_line("company.volatile.eurogoodies.magdeburg"):
self.selected_game = "ets2"
else:
self.selected_game = "ats"
self.check_config()
if self.owns is not False:
self.owns["base"] = True
companies = get_array_items(search_line("companies:"))
companies = util.get_array_items(util.search_line("companies:"))
for key, value in self.dlc.items():
if value in companies:
self.owns[key] = True
for key, value in self.basic_edits.items():
key.setText(get_value(search_line(value[1])))
key.setText(util.get_value(util.search_line(value[1])))
adr = self.get_adr(get_value(search_line("adr:")))
adr = self.get_adr(util.get_value(util.search_line("adr:")))
adr_list = ""
for i in range(6):
adr_list += adr[i] + "," if i != 5 else adr[i]
self.ui.adr_edit.setText(adr_list)
for key, value in self.skill_edits.items():
key.setText(get_value(search_line(value[1])))
key.setText(util.get_value(util.search_line(value[1])))
self.ui.apply.setEnabled(True)
self.ui.backup.setEnabled(True)
@@ -169,64 +185,57 @@ class MainWindow(QDialog, Ui_MainWindow):
file_path, file_name = QFileDialog.getOpenFileName(parent=self,
caption=self.tr("Choose your save file..."),
filter=self.tr("game.sii"))
self.clear_fields()
self.clear_form_data()
if file_path != "":
self.file_path = file_path
self.get_file_data(file_path)
else:
return
def change_configs(self):
box = QMessageBox(QMessageBox.Warning, "Warning", "Do you really change configs? "
"Your changes has been lost!")
box.addButton("Yes", QMessageBox.YesRole)
box.addButton("No", QMessageBox.NoRole)
if box.exec() == 0:
self.clear_fields()
self.selected_game = "ets2" if self.selected_game == "ats" else "ats"
self.ui.chosen_cfgs.setText("{} {}".format(self.chosen_cfg_text, self.selected_game.upper()))
self.check_config()
def recover_backup(self):
try:
backup = self.file_path + ".swbak"
f = open(backup)
with open(self.file_path, "w") as g:
g.write(f.read())
f.close()
remove(backup)
show_message(QMessageBox.Information, "Success", "Backup successfully recovered.")
self.get_file_data(self.file_path)
except IOError:
show_message(QMessageBox.Critical, "Error", "Backup not found.")
def update_on_startup(self):
with open(update_config_name, "w") as f:
f.write(str({"update_on_start": self.ui.updates_checkbox.isChecked()}))
def open_second_win(self):
second_win = SecondWindow(self.selected_game, self.owns, self)
second_win.exec()
second_win.exec_()
def recover_backup(self):
backup_path = self.file_path + ".swbak"
if not isfile(backup_path):
QMessageBox.critical(self, "Error", "Backup not found.")
return
with open(self.file_path, "w") as current:
with open(backup_path) as backup:
current.write(backup.read())
remove(backup_path)
QMessageBox.information(self, "Success", "Backup successfully recovered.")
self.get_file_data(self.file_path)
def apply_changes(self):
if not self.ui.dont_change_all_inf.isChecked():
for key, value in self.basic_edits.items():
if value[0].isChecked() is False:
set_value(search_line(value[1]), key.text())
value[0].setChecked(True)
if self.ui.adr_dont_change.isChecked() is False:
adr_set = self.get_adr_from_line()
if len(adr_set) < 6:
show_message(QMessageBox.Critical, "Error", "ADR can't have less than 6 elements.")
elif len(adr_set) > 6:
show_message(QMessageBox.Critical, "Error", "ADR can't have more than 6 elements.")
else:
adr_new = int("".join(adr_set), 2)
set_value(search_line("adr:"), str(adr_new))
for key, value in self.skill_edits.items():
if value[0].isChecked() is False:
set_value(search_line(value[1]), key.text())
value[0].setChecked(True)
if self.ui.dont_change_all_inf.isChecked():
return
for key, value in self.basic_edits.items():
if value[0].isChecked() is False:
util.set_value(util.search_line(value[1]), key.text())
value[0].setChecked(True)
if self.ui.adr_dont_change.isChecked() is False:
adr_set = self.get_adr_from_line()
if len(adr_set) < 6:
QMessageBox.critical(self, "Error", "ADR can't have less than 6 elements.")
elif len(adr_set) > 6:
QMessageBox.critical(self, "Error", "ADR can't have more than 6 elements.")
else:
adr_new = int("".join(adr_set), 2)
util.set_value(util.search_line("adr:"), str(adr_new))
for key, value in self.skill_edits.items():
if value[0].isChecked() is False:
util.set_value(util.search_line(value[1]), key.text())
value[0].setChecked(True)
backup = self.file_path + ".swbak"
with open(backup, "w") as f:
f.write(self.old_file)
with open(self.file_path, "w") as f:
f.write("\n".join(get_lines()))
show_message(QMessageBox.Information, "Success", "Changes successfully applied!")
f.write("\n".join(util.get_lines()))
QMessageBox.information(self, "Success", "Changes successfully applied!")
self.get_file_data(self.file_path)

66
module_parsing/script.py Normal file
View File

@@ -0,0 +1,66 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os
from ast import literal_eval
from requests import get
from dataIO import dataIO
from statics import github_link
from util import util
def get_response_result(url):
"""
Getting the result from a given url
:param url: place where we get data
:return: status code (True or False), response body
"""
response = get(url)
return response.status_code == 200, response
def check_path(path):
"""
Checks if the path exists (if not, creates it)
:param path: path to check
"""
current_path = os.getcwd()
for item in path.split("/"):
current_path = os.path.join(str(current_path), item)
if not os.path.exists(current_path):
if item.find(".json") > 0:
open(current_path, "w").close()
else:
os.mkdir(current_path)
def check_remote_hashes():
response_status, response = get_response_result(github_link + "configs/version.cfg")
if response_status:
remote_cfg = literal_eval(response.text)
need_update = []
for key, value in remote_cfg.items():
path = key.split("_")
path = "configs/{}/{}.json".format(path[0], path[1])
if util.generate_md5(path) != value:
need_update.append(path)
return need_update
return False
def update_configs():
update_list = check_remote_hashes()
if not update_list or len(update_list) == 0:
return
progress_bar = util.show_progress_bar("Download progress", "Downloading configs...", len(update_list))
for cfg in update_list:
check_path(cfg)
response_status, response = get_response_result(github_link + cfg)
if response_status:
remote_cfg = literal_eval(response.text)
if dataIO.is_valid_json(cfg) or os.path.exists(cfg):
dataIO.save_json(cfg, remote_cfg)
util.update_progress_bar(progress_bar)
util.update_progress_bar(progress_bar, len(update_list))

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<author>JDM170</author>
<class>SecondWindow</class>
<widget class="QDialog" name="SecondWindow">
<property name="geometry">
@@ -38,25 +39,6 @@
</rect>
</property>
<layout class="QGridLayout" name="garages_layout">
<item row="1" column="0">
<widget class="QTextBrowser" name="garages_text">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>11</pointsize>
</font>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="openLinks">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="garages_label">
<property name="font">
@@ -89,6 +71,25 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QTextEdit" name="garages_text">
<property name="font">
<font>
<family>Times New Roman</family>
<pointsize>11</pointsize>
</font>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="gridLayoutWidget_5">
@@ -118,7 +119,7 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QTextBrowser" name="cities_text">
<widget class="QTextEdit" name="cities_text">
<property name="font">
<font>
<family>Times New Roman</family>
@@ -131,8 +132,8 @@
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="openLinks">
<bool>false</bool>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
@@ -165,7 +166,7 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QTextBrowser" name="dealerships_text">
<widget class="QTextEdit" name="dealerships_text">
<property name="font">
<font>
<family>Times New Roman</family>
@@ -178,8 +179,8 @@
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="openLinks">
<bool>false</bool>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
@@ -212,7 +213,7 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QTextBrowser" name="agencies_text">
<widget class="QTextEdit" name="agencies_text">
<property name="font">
<font>
<family>Times New Roman</family>
@@ -225,8 +226,8 @@
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="openLinks">
<bool>false</bool>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>

297
module_second/script.py Normal file
View File

@@ -0,0 +1,297 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import QDialog
from .form import Ui_SecondWindow
from util import *
from dataIO import dataIO
garages_stat = {
"Small": [1, 1],
"Medium": [2, 3],
"Big": [3, 5]
}
class SecondWindow(QDialog, Ui_SecondWindow):
def __init__(self, selected_game, owns_list, parent=None):
# Setup UI
QDialog.__init__(self, parent, flags=(Qt.Window | Qt.WindowTitleHint | Qt.WindowCloseButtonHint))
Ui_SecondWindow.__init__(self)
self.ui = Ui_SecondWindow()
self.ui.setupUi(self)
self.owns = owns_list # From main window
# Checking config files
cfg_path = "configs/{}".format(selected_game)
dealers_path = "{}/dealers.json".format(cfg_path)
if dataIO.is_valid_json(dealers_path) is False:
self.dealers = False
self.ui.dealer_edit.setEnabled(False)
self.ui.dealer_add.setEnabled(False)
self.ui.dealer_add_all.setEnabled(False)
QMessageBox.warning(self, "Warning", "'dealers.json' from '{}' have errors or not found.\n"
"Dealers editing has been disabled".format(selected_game))
else:
self.dealers = []
self.dealers_file = dataIO.load_json(dealers_path)
agencies_path = "{}/agencies.json".format(cfg_path)
if dataIO.is_valid_json(agencies_path) is False:
self.agencies = False
self.ui.agency_edit.setEnabled(False)
self.ui.agency_add.setEnabled(False)
self.ui.agency_add_all.setEnabled(False)
QMessageBox.warning(self, "Warning", "'agencies.json' from '{}' have errors or not found.\n"
"Agencies editing has been disabled".format(selected_game))
else:
self.agencies = []
self.agencies_file = dataIO.load_json(agencies_path)
self.ui.garage_size.addItem("Small")
self.ui.garage_size.addItem("Medium")
self.ui.garage_size.addItem("Big")
self.da_statics = {
"dealer": [
self.dealers, # city_list
"unlocked_dealers:", # line_to_search
self.check_dealers, # check_func
],
"agency": [
self.agencies, # city_list
"unlocked_recruitments:", # line_to_search
self.check_agencies, # check_func
],
}
self.add_da_handlers = {
self.ui.dealer_add: [
"dealer",
self.ui.dealer_edit, # city_to_add
"Dealership", # message_variable
],
self.ui.dealer_add_all: [
"dealer",
"All dealerships unlocked.", # success_message
"Visiting dealers", # progress_message
],
self.ui.agency_add: [
"agency",
self.ui.agency_edit, # city_to_add
"Recruitment agency", # message_variable
],
self.ui.agency_add_all: [
"agency",
"All recruitment agencies unlocked.", # success_message
"Visiting agencies", # progress_message
],
}
# Connecting buttons
self.ui.garages_analyze.clicked.connect(self.check_garages)
self.ui.garage_add.clicked.connect(self.add_garage)
self.ui.garage_add_all.clicked.connect(self.add_all_garages)
self.ui.headquarter_change.clicked.connect(self.change_headquarter)
self.ui.city_add.clicked.connect(self.add_city)
self.ui.city_add_all.clicked.connect(self.add_all_cities)
self.ui.dealer_add.clicked.connect(self.add_da_clicked)
self.ui.agency_add.clicked.connect(self.add_da_clicked)
self.ui.dealer_add_all.clicked.connect(self.add_all_da_clicked)
self.ui.agency_add_all.clicked.connect(self.add_all_da_clicked)
if self.owns:
self.fill_list(self.owns, self.dealers, self.dealers_file)
self.fill_list(self.owns, self.agencies, self.agencies_file)
# Checking save-file
self.check_cities()
self.check_dealers()
self.check_agencies()
@staticmethod
def all_cities():
cities = []
for line in util.get_array_items(util.search_line("companies:")):
city = match(r"company.volatile.[a-z0-9_]+[.]([a-z_]+)", line).group(1)
if city not in cities:
cities.append(city)
return cities
@staticmethod
def add_vehicles_and_drivers(start_line, garage_size):
vehicles_array = util.search_line("vehicles:", start=start_line)
drivers_array = util.search_line("drivers:", start=start_line)
for i in range(1, garage_size + 1):
util.add_array_value(vehicles_array, "null")
util.add_array_value(drivers_array + i, "null")
@staticmethod
def purchased_garages():
garages = []
for index in util.search_all_lines("garage : garage."):
city = match(r"garage : garage.(.+) {$", util.get_lines(index)).group(1)
if util.get_value(util.search_line("status:", start=index)) != "0":
garages.append(city)
return garages
@staticmethod
def fill_list(owns, array, file):
if array is False:
return
for key in owns.keys():
if key not in file:
continue
for value in file[key]:
array.append(value)
def check_garage_size(self):
status_id, size = garages_stat[self.ui.garage_size.currentText()]
return str(status_id), size
def check_garages(self):
self.ui.garages_text.clear()
garages = self.purchased_garages()
for garage in garages:
self.ui.garages_text.append(garage)
self.ui.garages_text.scrollToAnchor(garages[0])
def add_garage(self):
garage = self.ui.garage_edit.text().lower()
if garage == "":
QMessageBox.critical(self, "Error", "Enter city name!")
return
self.ui.garage_edit.setText("")
current_garage = util.search_line("garage : garage." + garage + " {")
if current_garage is None:
QMessageBox.critical(self, "Error", "Garage in \"{}\" not found.".format(garage))
return
current_status = util.search_line_in_unit("status:", "garage." + garage)
if util.get_value(current_status) == "0":
new_status, size = self.check_garage_size()
util.set_value(current_status, new_status)
self.add_vehicles_and_drivers(current_garage, size)
QMessageBox.information(self, "Success", "Garage in \"{}\" successfully unlocked.".format(garage))
else:
QMessageBox.critical(self, "Error", "Garage in \"{}\" already unlocked.".format(garage))
def add_all_garages(self):
new_status, size = self.check_garage_size()
for item in util.get_array_items(util.search_line("garages:")):
item = match(r"garage.(.+)$", item).group(1)
current_garage = util.search_line("garage : garage." + item + " {")
current_status = util.search_line("status:", start=current_garage)
if util.get_value(current_status) == "0":
util.set_value(current_status, new_status)
self.add_vehicles_and_drivers(current_garage, size)
QMessageBox.information(self, "Success", "All garages successfully unlocked.")
def change_headquarter(self):
hq = self.ui.headquarter_edit.text().lower()
if hq == "":
QMessageBox.critical(self, "Error", "Enter city name!")
return
if util.get_value(util.search_line("hq_city:")) == hq:
QMessageBox.information(self, "Info", "Your headquarter is already in this city.")
elif hq not in self.purchased_garages():
QMessageBox.critical(self, "Error", "You need a garage in \"{}\" to set headquarter.".format(hq))
else:
util.set_value(util.search_line("hq_city:"), hq)
QMessageBox.information(self, "Success", "Headquarter successfully set to \"{}\".".format(hq))
def check_cities(self):
self.ui.headquarter_edit.setText(util.get_value(util.search_line("hq_city:")))
self.ui.cities_text.clear()
visited_cities = util.get_array_items(util.search_line("visited_cities:"))
if not visited_cities:
self.ui.cities_text.append("No cities visited yet.")
return
for city in visited_cities:
self.ui.cities_text.append(city)
self.ui.cities_text.scrollToAnchor(visited_cities[0])
def add_city(self):
city = self.ui.city_edit.text().lower()
if city == "":
QMessageBox.critical(self, "Error", "Enter city name!")
return
self.ui.city_edit.setText("")
if city not in util.get_array_items(util.search_line("visited_cities:")):
util.add_array_value(util.search_line("visited_cities:"), city)
util.add_array_value(util.search_line("visited_cities_count:"), "1")
QMessageBox.information(self, "Success", "City \"{}\" successfully visited.".format(city))
self.check_cities()
else:
QMessageBox.critical(self, "Error", "You've already visited \"{}\".".format(city))
def add_all_cities(self):
all_cities = self.all_cities()
visited_cities = util.get_array_items(util.search_line("visited_cities:"))
progress = util.show_progress_bar("Visiting cities", "Visiting cities...", len(all_cities)-len(visited_cities))
for city in all_cities:
if city not in visited_cities:
util.add_array_value(util.search_line("visited_cities:"), city)
util.add_array_value(util.search_line("visited_cities_count:"), "1")
util.update_progress_bar(progress)
QMessageBox.information(self, "Success", "All cities successfully visited.")
self.check_cities()
def check_dealers(self):
self.ui.dealerships_text.clear()
visited_dealers = util.get_array_items(util.search_line("unlocked_dealers:"))
if not visited_dealers:
self.ui.dealerships_text.append("No dealerships unlocked yet.")
return
for dealer in visited_dealers:
self.ui.dealerships_text.append(dealer)
self.ui.dealerships_text.scrollToAnchor(visited_dealers[0])
def check_agencies(self):
self.ui.agencies_text.clear()
visited_agencies = util.get_array_items(util.search_line("unlocked_recruitments:"))
if not visited_agencies:
self.ui.agencies_text.append("No recruitment agencies unlocked yet.")
return
for agency in visited_agencies:
self.ui.agencies_text.append(agency)
self.ui.agencies_text.scrollToAnchor(visited_agencies[0])
def add_da_clicked(self):
da_arr = self.add_da_handlers.get(self.sender())
if da_arr is None:
return
static_key, city_to_add, message_variable = da_arr
city_list, line_to_search, check_func = self.da_statics.get(static_key)
city_element = city_to_add.text().lower()
if not city_element:
QMessageBox.critical(self, "Error", "Enter city name!")
return
city_to_add.setText("")
if city_element not in city_list:
QMessageBox.critical(self, "Error", "There is no {} in that city.".format(message_variable.lower()))
elif city_element in util.get_array_items(util.search_line(line_to_search)):
QMessageBox.information(self, "Info", "{} in \"{}\" is already unlocked.".format(message_variable,
city_element))
else:
util.add_array_value(util.search_line(line_to_search), city_element)
QMessageBox.information(self, "Success", "{} in \"{}\" successfully unlocked."
"".format(message_variable, city_element))
check_func()
def add_all_da_clicked(self):
da_arr = self.add_da_handlers.get(self.sender())
if da_arr is None:
return
static_key, success_message, progress_message = da_arr
city_list, line_to_search, check_func = self.da_statics.get(static_key)
all_cities = self.all_cities()
array_line = util.search_line(line_to_search)
visited_cities = util.get_array_items(array_line)
progress = util.show_progress_bar(progress_message, progress_message+"...", len(all_cities)-len(visited_cities))
for element in city_list:
if (element in all_cities) and (element not in visited_cities):
util.add_array_value(array_line, element)
util.update_progress_bar(progress)
QMessageBox.information(self, "Success", success_message)
check_func()

View File

@@ -1,67 +0,0 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from requests import get
from hashlib import md5
from ast import literal_eval
import os
from dataIO import dataIO
from util import github_link, update_config_name
def send_response(txt):
response = get(txt)
return response if response.status_code == 200 else False
def generate_md5(fn):
hash_md5 = md5()
try:
with open(fn, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
except FileNotFoundError:
return False
def check_files(path):
temp = os.getcwd()
for item in path.split("/"):
temp = os.path.join(temp, item)
if not os.path.exists(temp):
if item.find(".json") > 0:
f = open(temp, "w")
f.close()
else:
os.mkdir(temp)
def check_remote_hashes():
response = send_response(github_link + "configs/version.cfg")
if response is not False:
remote_cfg = literal_eval(response.text)
need_to_be_updated = []
for key, value in remote_cfg.items():
path = key.split("_")
path = "configs/{}/{}.json".format(path[0], path[1])
if generate_md5(path) != value:
need_to_be_updated.append(path)
return need_to_be_updated
return False
def update_configs(is_save, cfg_list):
if is_save in (0, 1):
for cfg in cfg_list:
check_files(cfg)
response = send_response(github_link + cfg)
if response is not False:
remote_cfg = literal_eval(response.text)
if dataIO.is_valid_json(cfg) or os.path.exists(cfg):
dataIO.save_json(cfg, remote_cfg)
if is_save in (1, 3):
text = str({"answer_updates": is_save == 3,
"update_on_start": is_save == 1})
with open(update_config_name, "w") as f:
f.write(text)

17
requirements.txt Normal file
View File

@@ -0,0 +1,17 @@
altgraph==0.17.4
certifi==2023.11.17
charset-normalizer==3.3.2
cx_Freeze==7.0.0
cx-Logging==3.1.0
idna==3.7
lief==0.14.0
packaging==23.2
pefile==2023.2.7
pyinstaller==6.3.0
pyinstaller-hooks-contrib==2023.11
PyQt5==5.15.10
PyQt5-Qt5==5.15.2
PyQt5-sip==12.13.0
pywin32-ctypes==0.2.2
requests==2.32.0
urllib3==2.2.2

View File

@@ -1,256 +0,0 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QDialog
from .form import Ui_SecondWindow
from util import *
from dataIO import dataIO
garages_stat = {
"Small": [1, 1],
"Medium": [2, 3],
"Big": [3, 5]
}
class SecondWindow(QDialog, Ui_SecondWindow):
def __init__(self, selected_game, owns_list, parent=None):
# Setup UI
QDialog.__init__(self, parent, flags=Qt.Window)
Ui_SecondWindow.__init__(self)
self.ui = Ui_SecondWindow()
self.ui.setupUi(self)
self.owns = owns_list # From main window
# Checking files
cfg_path = "configs/{}".format(selected_game)
dealers_path = "{}/dealers.json".format(cfg_path)
agencies_path = "{}/agencies.json".format(cfg_path)
if dataIO.is_valid_json(dealers_path) is False:
self.dealers = False
self.ui.dealer_edit.setEnabled(False)
self.ui.dealer_add.setEnabled(False)
self.ui.dealer_add_all.setEnabled(False)
show_message(QMessageBox.Warning, "Warning", "'dealers.json' from '{}' not found, dealers "
"editing has been disabled".format(selected_game))
else:
self.dealers = []
self.dealers_file = dataIO.load_json(dealers_path)
if dataIO.is_valid_json(agencies_path) is False:
self.agencies = False
self.ui.agency_edit.setEnabled(False)
self.ui.agency_add.setEnabled(False)
self.ui.agency_add_all.setEnabled(False)
show_message(QMessageBox.Warning, "Warning", "'agencies.json' from '{}' not found, agencies "
"editing has been disabled".format(selected_game))
else:
self.agencies = []
self.agencies_file = dataIO.load_json(agencies_path)
self.ui.garage_size.addItem("Small")
self.ui.garage_size.addItem("Medium")
self.ui.garage_size.addItem("Big")
# Dealers and agencies properties
self.da_array = {
self.ui.dealer_add: [self.ui.dealer_edit, "unlocked_dealers:", "Dealership", self.dealers,
self.check_dealers],
self.ui.agency_add: [self.ui.agency_edit, "unlocked_recruitments:", "Recruitment agency",
self.agencies, self.check_agencies],
}
# Connecting buttons
self.ui.garages_analyze.clicked.connect(self.check_garages)
self.ui.garage_add.clicked.connect(self.add_garage)
self.ui.garage_add_all.clicked.connect(self.add_all_garages)
self.ui.headquarter_change.clicked.connect(self.change_headquarter)
self.ui.city_add.clicked.connect(self.add_city)
self.ui.city_add_all.clicked.connect(self.add_all_cities)
self.ui.dealer_add.clicked.connect(self.da_clicked)
self.ui.dealer_add_all.clicked.connect(self.add_all_dealers)
self.ui.agency_add.clicked.connect(self.da_clicked)
self.ui.agency_add_all.clicked.connect(self.add_all_agencies)
if self.owns:
self.fill_list(self.dealers, self.dealers_file)
self.fill_list(self.agencies, self.agencies_file)
# Checking save-file
self.check_cities()
self.check_dealers()
self.check_agencies()
@staticmethod
def purchased_garages():
garages = []
for index in search_all_lines("garage : garage."):
city = match(r"garage : garage.(.+) {$", get_lines(index)).group(1)
if get_value(search_line("status:", start=index)) != "0":
garages.append(city)
return garages
@staticmethod
def all_cities():
cities = []
for line in get_array_items(search_line("companies:")):
city = match(r"company.volatile.[a-z0-9_]+[.]([a-z_]+)", line).group(1)
if city not in cities:
cities.append(city)
return cities
def fill_list(self, array, file):
if array is False:
return
for key in self.owns.keys():
if key not in file:
continue
for value in file[key]:
array.append(value)
def check_garage_size(self):
stat = garages_stat[self.ui.garage_size.currentText()]
return str(stat[0]), stat[1]
def check_garages(self):
self.ui.garages_text.clear()
for garage in self.purchased_garages():
self.ui.garages_text.append(garage)
def add_garage(self):
garage = self.ui.garage_edit.text().lower()
if garage is "":
show_message(QMessageBox.Critical, "Error", "Enter a name for the city.")
return
self.ui.garage_edit.setText("")
reg_garage = "garage." + garage
current_status = search_line_in_unit("status:", reg_garage)
if get_value(current_status) == "0":
new_status, size = self.check_garage_size()
set_value(current_status, new_status)
vehicles_array = search_line_in_unit("vehicles:", reg_garage)
drivers_array = search_line_in_unit("drivers:", reg_garage)
for i in range(1, size+1):
add_array_value(vehicles_array, "null")
add_array_value(drivers_array+i, "null")
show_message(QMessageBox.Information, "Success", "Garage in \"{}\" successfully unlocked.".format(garage))
else:
show_message(QMessageBox.Critical, "Error", "Garage in \"{}\" already unlocked.".format(garage))
def add_all_garages(self):
new_status, size = self.check_garage_size()
for item in get_array_items(search_line("garages:")):
item = match(r"garage.(.+)$", item).group(1)
current_garage = search_line("garage : garage."+item+" {")
current_status = search_line("status:", start=current_garage)
if get_value(current_status) == "0":
set_value(current_status, new_status)
vehicles_array = search_line("vehicles:", start=current_garage)
drivers_array = search_line("drivers:", start=current_garage)
for i in range(1, size+1):
add_array_value(vehicles_array, "null")
add_array_value(drivers_array+i, "null")
show_message(QMessageBox.Information, "Success", "All garages successfully unlocked.")
def change_headquarter(self):
hq = self.ui.headquarter_edit.text().lower()
if hq is "":
show_message(QMessageBox.Critical, "Error", "Enter a name for the city.")
return
if get_value(search_line("hq_city:")) == hq:
show_message(QMessageBox.Information, "Info", "Your headquarter is already in this city")
elif hq not in self.purchased_garages():
show_message(QMessageBox.Critical, "Error", "You need to own the garage in this city.")
else:
set_value(search_line("hq_city:"), hq)
show_message(QMessageBox.Information, "Success", "Headquarter successfully set to \"{}\".".format(hq))
def check_cities(self):
self.ui.headquarter_edit.setText(get_value(search_line("hq_city:")))
self.ui.cities_text.clear()
visited_cities = get_array_items(search_line("visited_cities:"))
if not visited_cities:
self.ui.cities_text.append("No cities visited yet.")
return
for city in visited_cities:
self.ui.cities_text.append(city)
def add_city(self):
city = self.ui.city_edit.text().lower()
if city is "":
show_message(QMessageBox.Critical, "Error", "Enter a name for the city.")
return
self.ui.city_edit.setText("")
if city not in get_array_items(search_line("visited_cities:")):
add_array_value(search_line("visited_cities:"), city)
add_array_value(search_line("visited_cities_count:"), "1")
show_message(QMessageBox.Information, "Success", "City \"{}\" successfully visited.".format(city))
self.check_cities()
else:
show_message(QMessageBox.Critical, "Error", "You already visited \"{}\".".format(city))
def add_all_cities(self):
visited_cities = get_array_items(search_line("visited_cities:"))
for city in self.all_cities():
if city not in visited_cities:
add_array_value(search_line("visited_cities:"), city)
add_array_value(search_line("visited_cities_count:"), "1")
show_message(QMessageBox.Information, "Success", "All cities successfully visited.")
self.check_cities()
def check_dealers(self):
self.ui.dealerships_text.clear()
visited_dealers = get_array_items(search_line("unlocked_dealers:"))
if not visited_dealers:
self.ui.dealerships_text.append("No dealerships unlocked yet.")
return
for dealer in visited_dealers:
self.ui.dealerships_text.append(dealer)
def add_all_dealers(self):
all_cities = self.all_cities()
visited_dealers = get_array_items(search_line("unlocked_dealers:"))
for dealer in self.dealers:
if dealer in all_cities and dealer not in visited_dealers:
add_array_value(search_line("unlocked_dealers:"), dealer)
show_message(QMessageBox.Information, "Success", "All dealerships unlocked.")
self.check_dealers()
def check_agencies(self):
self.ui.agencies_text.clear()
visited_agencies = get_array_items(search_line("unlocked_recruitments:"))
if not visited_agencies:
self.ui.agencies_text.append("No recruitment agencies unlocked yet.")
return
for agency in visited_agencies:
self.ui.agencies_text.append(agency)
def add_all_agencies(self):
all_cities = self.all_cities()
visited_agencies = get_array_items(search_line("unlocked_recruitments:"))
for agency in self.agencies:
if agency in all_cities and agency not in visited_agencies:
add_array_value(search_line("unlocked_recruitments:"), agency)
show_message(QMessageBox.Information, "Success", "All recruitment agencies unlocked.")
self.check_agencies()
def da_clicked(self):
da_arr = self.da_array.get(self.sender())
if da_arr is None:
return
edit, file_var, message_var = da_arr[0], da_arr[1], da_arr[2]
city_element = edit.text().lower()
if not city_element:
show_message(QMessageBox.Critical, "Error", "Enter a name for the city.")
return
edit.setText("")
if city_element not in da_arr[3]:
show_message(QMessageBox.Critical, "Error", "There is no {} in that city.".format(message_var.lower()))
elif city_element in get_array_items(search_line(file_var)):
show_message(QMessageBox.Information, "Info", "{} is already unlocked.".format(message_var))
else:
add_array_value(search_line(file_var), city_element)
show_message(QMessageBox.Information, "Success", "{} in \"{}\" successfully unlocked."
"".format(message_var, city_element))
da_arr[4]()

View File

@@ -8,26 +8,33 @@ base = None
if platform == 'win32':
base = 'Win32GUI'
executables = [Executable('__init__.py', targetName='SaveWizard.exe', base=base)]
executables = [
Executable('init_main_program.py', target_name='SaveWizard.exe', base=base),
Executable('init_config_editor.py', target_name='SaveWizard_Config_Editor.exe', base=base)
]
excludes = ['html', 'pydoc_data', 'unittest', 'xml', 'pwd', 'shlex', 'platform', 'webbrowser', 'pydoc', 'tty',
'inspect', 'doctest', 'plistlib', 'subprocess', 'bz2', '_strptime', 'dummy_threading']
excludes = ['html', 'pydoc_data', 'unittest', 'xml', 'pwd', 'shlex', 'platform', 'webbrowser', 'pydoc',
'tty', 'doctest', 'plistlib', 'subprocess', 'bz2', '_strptime', 'dummy_threading']
includes = ['pkgutil', 'enum', 'queue', 'PyQt5.sip']
includes = ['pkgutil', 'enum', 'queue']
zip_include_packages = [
# Stock modules
'collections', 'encodings', 'importlib', 'json', 'hashlib', 'selectors', 'select', 'http', 'email', 'datetime',
'calendar', 'urllib', 'posixpath', 'tempfile', 'shutil', 'copy', 'stringprep', 'socket', 'ast',
'calendar', 'urllib', 'posixpath', 'tempfile', 'shutil', 'copy', 'stringprep', 'socket', 'ast', 'ssl', 'ctypes',
# PyQt5
'PyQt5',
# Modules for parsing cfg's
'requests', 'logging', 'certifi', 'chardet', 'idna', 'urllib3',
'requests', 'logging', 'certifi', 'chardet', 'idna', 'urllib3', 'inspect',
# Self-written modules
'parsing', 'choice', 'main', 'second'
'module_parsing', 'module_main', 'module_second', 'module_config_editor'
]
include_files = ['dlls/imageformats', 'dlls/platforms', 'dlls/styles', 'SII_Decrypt.exe', 'configs']
include_files = [
'SII_Decrypt.dll',
('configs/ats', 'configs/ats'),
('configs/ets2', 'configs/ets2')
]
options = {
'build_exe': {
@@ -42,7 +49,7 @@ options = {
setup(
name='SaveWizard',
version='1.2',
version='1.4.1',
description='For editing ETS2 sii files',
executables=executables,
options=options,

6
statics.py Normal file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
update_config_name = "update.cfg"
github_link = "https://raw.githubusercontent.com/JDM170/SaveWizard/configs/"
hash_chunk_size = 4096

231
util.py
View File

@@ -1,130 +1,133 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from re import search, match, sub
from PyQt5.QtWidgets import QMessageBox
github_link = "https://raw.githubusercontent.com/JDM170/SaveWizard/master/"
update_config_name = "update.cfg"
lines = []
from os.path import isfile
from re import search, match
# from re import search, match, sub
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QMessageBox, QProgressDialog, QApplication
)
from hashlib import md5
from statics import hash_chunk_size
# Custom functions
def set_lines(new_lines):
global lines
lines = new_lines
class CustomFuncs:
# Custom functions
def __init__(self):
self.lines = []
def set_lines(self, new_lines):
self.lines = new_lines
def get_lines(index=None):
global lines
if index is not None:
return lines[index]
return lines
def get_lines(self, index=None):
if index is not None:
return self.lines[index]
return self.lines
@staticmethod
def generate_md5(fn):
if not isfile(fn):
return False
hash_md5 = md5()
with open(fn, "rb") as f:
for chunk in iter(lambda: f.read(hash_chunk_size), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
def show_message(icon, title, text):
box = QMessageBox(icon, title, text, QMessageBox.Ok)
box.exec()
@staticmethod
def show_progress_bar(title, text, length):
if (not title) or (not text) or (not length) or (length <= 0):
return
progress_bar = QProgressDialog(text, None, 0, length, flags=Qt.Window | Qt.WindowTitleHint)
progress_bar.setWindowTitle(title)
progress_bar.setWindowModality(Qt.WindowModal)
progress_bar.show()
return progress_bar
@staticmethod
def update_progress_bar(progress_bar, value=1):
if not progress_bar:
return
progress_bar.setValue(progress_bar.value() + value)
QApplication.processEvents()
# Stock functions
def search_line(term, start=0, cancel=r"this_string_must_not_exist"):
global lines
if search(term, lines[start]):
return start
start += 1
while start <= len(lines) - 1:
if search(term, lines[start]):
# Stock functions
def search_line(self, term, start=0, cancel=r"this_string_must_not_exist"):
if search(term, self.lines[start]):
return start
if search(cancel, lines[start]):
return None
start += 1
return None
def search_line_in_unit(term, unit):
global lines
line = search_line(" : " + unit + " {")
return search_line(term, start=line, cancel="}")
def search_all_lines(term):
global lines
matches = []
line = 0
while search_line(term, start=line + 1):
line = search_line(term, start=line + 1)
matches.append(line)
if matches is None:
while start <= len(self.lines) - 1:
if search(term, self.lines[start]):
return start
if search(cancel, self.lines[start]):
return None
start += 1
return None
return matches
def search_line_in_unit(self, term, unit):
line = self.search_line(" : " + unit + " {")
return self.search_line(term, start=line, cancel="}")
def search_all_lines(self, term):
matches = []
line = 0
while self.search_line(term, start=line + 1):
line = self.search_line(term, start=line + 1)
matches.append(line)
if matches is None:
return None
return matches
def get_value(self, line):
return search(r": (.+)$", self.lines[line]).group(1)
def set_value(self, line, value):
name = match(r"(.+):", self.lines[line]).group(1)
self.lines[line] = name + ": " + value
# def get_unit_name(self, line):
# return search(r" : (.+) {$", self.lines[line]).group(1)
def get_array_length(self, line):
return int(search(r": ([0-9]+)$", self.lines[line]).group(1))
# def get_array_value_by_index(self, line, index):
# return search(r": (.+)$", self.lines[line + index + 1]).group(1)
# def get_array_index_by_value(self, line, value):
# count = 0
# for i in range(self.get_array_length(line)):
# if self.get_value(line + count + 1) == value:
# return count
# count += 1
# return None
def get_array_items(self, line):
items = []
for i in range(self.get_array_length(line)):
items.append(search(r": (.+)$", self.lines[line + i + 1]).group(1))
if items is None:
return None
return items
def add_array_value(self, line, value):
name = match(r"(.+):", self.lines[line]).group(1)
count = self.get_array_length(line)
self.lines[line] = name + ": " + str(count + 1)
self.lines.insert(line + count + 1, name + "[" + str(count) + "]: " + value)
# def remove_array_value(self, line, value):
# name = match(r"(.+):", self.lines[line]).group(1)
# del self.lines[line + 1 + self.get_array_index_by_value(line, value)]
# count = self.get_array_length(line)
# self.lines[line] = name + ": " + str(count - 1)
# for i in range(count):
# self.lines[line + i + 1] = sub(r"\[[0-9]+]", "[" + str(i) + "]", lines[line + i + 1])
# def change_array_value(self, line, index, value):
# line += index + 1
# self.set_value(line, value)
def get_value(line):
global lines
return search(r": (.+)$", lines[line]).group(1)
def set_value(line, value):
global lines
name = match(r"(.+):", lines[line]).group(1)
lines[line] = name + ": " + value
def get_unit_name(line):
global lines
return search(r" : (.+) {$", lines[line]).group(1)
def get_array_length(line):
global lines
return int(search(r": ([0-9]+)$", lines[line]).group(1))
def get_array_value_by_index(line, index):
global lines
return search(r": (.+)$", lines[line + index + 1]).group(1)
def get_array_index_by_value(line, value):
global lines
count = 0
for i in range(get_array_length(line)):
if get_value(line + count + 1) == value:
return count
count += 1
return None
def get_array_items(line):
global lines
items = []
for i in range(get_array_length(line)):
items.append(search(r": (.+)$", lines[line + i + 1]).group(1))
if items is None:
return None
return items
def add_array_value(line, value):
global lines
name = match(r"(.+):", lines[line]).group(1)
count = get_array_length(line)
lines[line] = name + ": " + str(count + 1)
lines.insert(line + count + 1, name + "[" + str(count) + "]: " + value)
def remove_array_value(line, value):
global lines
name = match(r"(.+):", lines[line]).group(1)
del lines[line + 1 + get_array_index_by_value(line, value)]
count = get_array_length(line)
lines[line] = name + ": " + str(count - 1)
for i in range(count):
lines[line + i + 1] = sub(r"\[[0-9]+\]", "[" + str(i) + "]", lines[line + i + 1])
def change_array_value(line, index, value):
global lines
line += index + 1
set_value(line, value)
util = CustomFuncs()