* Добавлена архитектура сборки x86 * Ссылка на репозиторий с конфигурациями вынесена в конфигурационный файл (update.cfg) * Обновлен механизм создания и взаимодействия с файлом конфигурации (update.cfg) * Добавлена обработка ошибки декодирования файла при попытке его открыть Signed-off-by: Lev Rusanov <30170278+JDM170@users.noreply.github.com>
330 lines
14 KiB
C#
330 lines
14 KiB
C#
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows.Forms;
|
|
|
|
namespace SaveWizard
|
|
{
|
|
public partial class MainForm: Form
|
|
{
|
|
private readonly string config_file_name = "update.cfg";
|
|
|
|
// SIIDEC_RESULT_GENERIC_ERROR = -1;
|
|
// SIIDEC_RESULT_SUCCESS = 0;
|
|
// SIIDEC_RESULT_FORMAT_PLAINTEXT = 1;
|
|
// SIIDEC_RESULT_FORMAT_ENCRYPTED = 2;
|
|
// SIIDEC_RESULT_FORMAT_BINARY = 3;
|
|
// SIIDEC_RESULT_FORMAT_3NK = 4;
|
|
// SIIDEC_RESULT_FORMAT_UNKNOWN = 10;
|
|
// SIIDEC_RESULT_TOO_FEW_DATA = 11;
|
|
// SIIDEC_RESULT_BUFFER_TOO_SMALL = 12;
|
|
|
|
// SIIDEC_RESULT_GENERIC_ERROR - an unhandled exception have occured
|
|
// SIIDEC_RESULT_FORMAT_PLAINTEXT - plain-text SII file
|
|
// SIIDEC_RESULT_FORMAT_ENCRYPTED - encrypted SII file
|
|
// SIIDEC_RESULT_FORMAT_BINARY - binary form of SII file
|
|
// SIIDEC_RESULT_FORMAT_3NK - file is an 3nK-encoded SII file
|
|
// SIIDEC_RESULT_FORMAT_UNKNOWN - file of an unknown format
|
|
// SIIDEC_RESULT_TOO_FEW_DATA - file is too small to contain valid data for its format
|
|
[DllImport("SII_Decrypt.dll")]
|
|
public static extern int GetFileFormat(string FileName);
|
|
|
|
// SIIDEC_RESULT_GENERIC_ERROR - an unhandled exception have occured
|
|
// SIIDEC_RESULT_SUCCESS - input file was successfully decrypted and/or decoded and result stored in the output file
|
|
// SIIDEC_RESULT_FORMAT_PLAINTEXT - input file contains plain-text SII file (does not need decryption or decoding)
|
|
// SIIDEC_RESULT_FORMAT_UNKNOWN - input file is of an uknown format
|
|
// SIIDEC_RESULT_TOO_FEW_DATA - input file is too small to contain a valid encrypted or encoded SII file
|
|
[DllImport("SII_Decrypt.dll")]
|
|
public static extern int DecryptAndDecodeFile(string InputFile, string OutputFile);
|
|
|
|
private Dictionary<TextBox, WindowItem> items = null;
|
|
private string opened_file_path, selected_game;
|
|
private Dictionary<string, bool> owns = null;
|
|
|
|
public MainForm()
|
|
{
|
|
InitializeComponent();
|
|
// Test stuff
|
|
//string path = Path.Combine(Environment.CurrentDirectory, "configs");
|
|
//if (Directory.Exists(path))
|
|
// Directory.Delete(path, true);
|
|
//path = Path.Combine(Environment.CurrentDirectory, "update.cfg");
|
|
//if (File.Exists(path))
|
|
// File.Delete(path);
|
|
}
|
|
|
|
private class WindowItem
|
|
{
|
|
private readonly CheckBox Check;
|
|
private readonly string Str;
|
|
|
|
public WindowItem(CheckBox _check, string _str)
|
|
{
|
|
Check = _check;
|
|
Str = _str;
|
|
}
|
|
|
|
public CheckBox GetCheck()
|
|
{
|
|
return Check;
|
|
}
|
|
|
|
public string GetString()
|
|
{
|
|
return Str;
|
|
}
|
|
}
|
|
|
|
private void boxTextChanged(object sender, EventArgs e)
|
|
{
|
|
TextBox _sender = sender as TextBox;
|
|
if (_sender != txt_adr)
|
|
items[_sender].GetCheck().Checked = false;
|
|
else
|
|
chk_adr.Checked = false;
|
|
}
|
|
|
|
private void ValidateBasic(object sender, KeyPressEventArgs e)
|
|
{
|
|
//if (!(e.KeyChar >= '0' && e.KeyChar <= '9') && !char.IsControl(e.KeyChar))
|
|
if (!(e.KeyChar >= '0' && e.KeyChar <= '9') && e.KeyChar != (char)Keys.Back)
|
|
e.Handled = true;
|
|
}
|
|
|
|
private void ValidateSkills(object sender, KeyPressEventArgs e)
|
|
{
|
|
//if (!(e.KeyChar >= '0' && e.KeyChar <= '6') && !char.IsControl(e.KeyChar))
|
|
if (!(e.KeyChar >= '0' && e.KeyChar <= '6') && e.KeyChar != (char)Keys.Back)
|
|
e.Handled = true;
|
|
}
|
|
|
|
private List<string> GetADR(string value)
|
|
{
|
|
string binaryCode = Convert.ToString(int.Parse(value), 2);
|
|
binaryCode = new string('0', 6 - binaryCode.Length) + binaryCode;
|
|
List<string> result = new List<string>();
|
|
foreach (char character in binaryCode)
|
|
result.Add(character.ToString());
|
|
return result;
|
|
}
|
|
|
|
private void GetFileData(string filename)
|
|
{
|
|
RegexHandler.FillLines(File.ReadAllLines(filename).ToList());
|
|
|
|
foreach (KeyValuePair<TextBox, WindowItem> item in items)
|
|
{
|
|
item.Key.Text = RegexHandler.GetValue(RegexHandler.SearchLine(item.Value.GetString()));
|
|
item.Value.GetCheck().Checked = true;
|
|
}
|
|
|
|
txt_adr.Text = string.Join(",", GetADR(RegexHandler.GetValue(RegexHandler.SearchLine("adr:"))));
|
|
chk_adr.Checked = true;
|
|
|
|
if (RegexHandler.SearchLine("company.volatile.stokes.calais") != 0)
|
|
selected_game = "ets2";
|
|
else if (RegexHandler.SearchLine("company.volatile.ed_mkt.elko") != 0)
|
|
selected_game = "ats";
|
|
else
|
|
selected_game = null;
|
|
if (selected_game != null)
|
|
{
|
|
string config_path = $"configs/{selected_game}/dlc.json";
|
|
if (File.Exists(config_path))
|
|
{
|
|
Dictionary<string, string> dlc = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(config_path));
|
|
owns = new Dictionary<string, bool>
|
|
{
|
|
{ "base", true }
|
|
};
|
|
List<string> companies = RegexHandler.GetArrayItems("companies:");
|
|
foreach (string company in companies)
|
|
foreach (KeyValuePair<string, string> item in dlc)
|
|
if (company.Contains(item.Value))
|
|
owns[item.Key] = true;
|
|
}
|
|
else
|
|
Utils.ShowError($"'dlc.json' from '{selected_game}' have errors or not found, functionality has been limited");
|
|
}
|
|
|
|
btn_unlock_garages.Enabled = true;
|
|
btn_recover_backup.Enabled = true;
|
|
btn_apply_changes.Enabled = true;
|
|
}
|
|
|
|
private void ClearData()
|
|
{
|
|
opened_file_path = null;
|
|
RegexHandler.FillLines(null);
|
|
selected_game = null;
|
|
owns = null;
|
|
foreach (KeyValuePair<TextBox, WindowItem> item in items)
|
|
{
|
|
item.Key.Text = "";
|
|
item.Value.GetCheck().Checked = true;
|
|
}
|
|
txt_adr.Text = "";
|
|
chk_adr.Checked = true;
|
|
btn_unlock_garages.Enabled = false;
|
|
btn_recover_backup.Enabled = false;
|
|
btn_apply_changes.Enabled = false;
|
|
}
|
|
|
|
private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
|
|
{
|
|
Application.Exit();
|
|
}
|
|
|
|
private void MainForm_Load(object sender, EventArgs e)
|
|
{
|
|
if (!File.Exists("SII_Decrypt.dll"))
|
|
{
|
|
Utils.ShowError("SII_Decrypt.dll not found! Place dll file near this executable.");
|
|
Close();
|
|
}
|
|
|
|
items = new Dictionary<TextBox, WindowItem>
|
|
{
|
|
{ txt_money, new WindowItem(chk_money, "money_account:") },
|
|
{ txt_experience, new WindowItem(chk_experience, "experience_points:") },
|
|
{ txt_loan_limit, new WindowItem(chk_loan_limit, "loan_limit:") },
|
|
{ txt_long_distance, new WindowItem(chk_long_distance, "long_dist:") },
|
|
{ txt_high_value_cargo, new WindowItem(chk_high_value_cargo, "heavy:") },
|
|
{ txt_fragile_cargo, new WindowItem(chk_fragile_cargo, "fragile:") },
|
|
{ txt_urgent_delivery, new WindowItem(chk_urgent_delivery, "urgent:") },
|
|
{ txt_ecodriving, new WindowItem(chk_ecodriving, "mechanical:") },
|
|
};
|
|
KeyPressEventHandler basic = new KeyPressEventHandler(ValidateBasic);
|
|
txt_money.KeyPress += basic;
|
|
txt_experience.KeyPress += basic;
|
|
txt_loan_limit.KeyPress += basic;
|
|
//txt_adr.KeyPress += new KeyPressEventHandler(ValidateADR);
|
|
KeyPressEventHandler skills = new KeyPressEventHandler(ValidateSkills);
|
|
txt_long_distance.KeyPress += skills;
|
|
txt_high_value_cargo.KeyPress += skills;
|
|
txt_fragile_cargo.KeyPress += skills;
|
|
txt_urgent_delivery.KeyPress += skills;
|
|
txt_ecodriving.KeyPress += skills;
|
|
foreach (TextBox txtbox in items.Keys)
|
|
txtbox.TextChanged += boxTextChanged;
|
|
txt_adr.TextChanged += boxTextChanged;
|
|
string config_path = Path.Combine(Environment.CurrentDirectory, config_file_name);
|
|
if (File.Exists(config_path))
|
|
{
|
|
Dictionary<string, object> update_conf = JsonConvert.DeserializeObject<Dictionary<string, object>>(File.ReadAllText(config_path));
|
|
if ((bool)update_conf["update_on_start"])
|
|
{
|
|
chk_update_on_start.Checked = true;
|
|
UpdateForm window = new UpdateForm((string)update_conf["respository_link"]);
|
|
window.ShowDialog();
|
|
window.Focus();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
File.WriteAllText(config_path,
|
|
JsonConvert.SerializeObject(new Dictionary<string, object>
|
|
{
|
|
{ "update_on_start", false },
|
|
{ "respository_link", "https://raw.githubusercontent.com/JDM170/SaveWizard_configs/main/" }
|
|
}
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
private void chk_update_on_start_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
string config_path = Path.Combine(Environment.CurrentDirectory, config_file_name);
|
|
if (!File.Exists(config_path))
|
|
return;
|
|
Dictionary<string, object> fileData = JsonConvert.DeserializeObject<Dictionary<string, object>>(File.ReadAllText(config_path));
|
|
fileData["update_on_start"] = chk_update_on_start.Checked;
|
|
File.WriteAllText(config_path, JsonConvert.SerializeObject(fileData));
|
|
}
|
|
|
|
private void btn_open_save_Click(object sender, EventArgs e)
|
|
{
|
|
ClearData();
|
|
OpenFileDialog ofd = new OpenFileDialog()
|
|
{
|
|
Title = "Выберите файл сохранения",
|
|
Filter = "Файл game.sii|game.sii",
|
|
Multiselect = false,
|
|
};
|
|
if (ofd.ShowDialog() == DialogResult.OK)
|
|
{
|
|
int fileFormat = GetFileFormat(ofd.FileName);
|
|
if (fileFormat == -1)
|
|
{
|
|
Utils.ShowError("The file name cannot contain spaces or special characters.");
|
|
return;
|
|
}
|
|
if (fileFormat >= 2 && fileFormat <= 4)
|
|
{
|
|
if (DecryptAndDecodeFile(ofd.FileName, ofd.FileName) != 0)
|
|
{
|
|
Utils.ShowError("Something went wrong with decrypting file. Try again.");
|
|
return;
|
|
}
|
|
}
|
|
GetFileData(ofd.FileName);
|
|
opened_file_path = ofd.FileName;
|
|
}
|
|
}
|
|
|
|
private void btn_unlock_garages_Click(object sender, EventArgs e)
|
|
{
|
|
SecondForm dlg = new SecondForm(selected_game, owns);
|
|
dlg.ShowDialog();
|
|
dlg.Focus();
|
|
}
|
|
|
|
private void btn_recover_backup_Click(object sender, EventArgs e)
|
|
{
|
|
string backup_path = opened_file_path + ".swbak";
|
|
if (!File.Exists(backup_path))
|
|
{
|
|
Utils.ShowError("Backup not found.");
|
|
return;
|
|
}
|
|
File.WriteAllLines(opened_file_path, File.ReadAllLines(backup_path));
|
|
File.Delete(backup_path);
|
|
Utils.ShowInfo("Backup successfully recovered.");
|
|
GetFileData(opened_file_path);
|
|
}
|
|
|
|
private void btn_apply_changes_Click(object sender, EventArgs e)
|
|
{
|
|
if (!chk_adr.Checked)
|
|
{
|
|
List<char> adrList = txt_adr.Text.ToList();
|
|
adrList.RemoveAll(i => i == ' ' || i == ',' || i == '.');
|
|
if (adrList.Count < 6)
|
|
{
|
|
Utils.ShowError("ADR can't have less than 6 elements.");
|
|
}
|
|
else if (adrList.Count > 6)
|
|
{
|
|
Utils.ShowError("ADR can't have more than 6 elements.");
|
|
}
|
|
else
|
|
{
|
|
int adrNew = Convert.ToInt32(string.Join("", adrList), 2);
|
|
RegexHandler.SetValue(RegexHandler.SearchLine("adr:"), adrNew.ToString());
|
|
}
|
|
}
|
|
foreach (KeyValuePair<TextBox, WindowItem> item in items)
|
|
if (!item.Value.GetCheck().Checked)
|
|
RegexHandler.SetValue(RegexHandler.SearchLine(item.Value.GetString()), item.Key.Text);
|
|
File.WriteAllLines(opened_file_path + ".swbak", RegexHandler.GetBackup());
|
|
File.WriteAllLines(opened_file_path, RegexHandler.GetAllLines());
|
|
Utils.ShowInfo("Changes successfully applied.");
|
|
GetFileData(opened_file_path);
|
|
}
|
|
}
|
|
}
|