diff --git a/Pf2eDataScrapper/App/Attributes.cs b/Pf2eDataScrapper/App/Attributes.cs
new file mode 100644
index 0000000..df60b8b
--- /dev/null
+++ b/Pf2eDataScrapper/App/Attributes.cs
@@ -0,0 +1,62 @@
+namespace Pf2eDataScrapper.App;
+
+///
+/// Общий аттрибут обработчика.
+///
+/// Название обработчика.
+/// Названия обработчиков, которые должны быть выполнены до запуска этого обработчика.
+[AttributeUsage(AttributeTargets.Class)]
+public class ProcessAttribute(string name, ICollection dependencies) : Attribute
+{
+ ///
+ /// Название обработчика.
+ ///
+ public string Name { get; init; } = name;
+
+ ///
+ /// Коллекция названий обработчиков, которые должны быть выполнены до этого оброботчика.
+ ///
+ public ICollection Dependencies { get; init; } = dependencies;
+
+ public ProcessAttribute(string name)
+ : this(name, []) { }
+}
+
+///
+/// Аттрибут обработчика для уточнения группы.
+///
+/// Группа обработчиков, к которому относится обработчик.
+[AttributeUsage(AttributeTargets.Class)]
+internal class ProcessorGroupAttribute(ProcessorGroupEnum group) : Attribute
+{
+ ///
+ /// Название обработчика, к которому относится обработчик.
+ ///
+ public ProcessorGroupEnum Group { get; init; } = group;
+}
+
+///
+/// Аттрибут обработчика для уточнения списка зависимостей.
+///
+/// Список названий зависимостей.
+[AttributeUsage(AttributeTargets.Class)]
+internal class ProcessorDependenciesAttribute(ICollection dependencies) : Attribute
+{
+ ///
+ /// Коллекция названий обработчиков, которые должны быть выполнены до этого оброботчика.
+ ///
+ public ICollection Dependencies { get; init; } = dependencies;
+}
+
+///
+/// Аттрибут обработчика для внутреннего типа элемента.
+///
+/// Внутренний типа элемента.
+[AttributeUsage(AttributeTargets.Class)]
+internal class ProcessorInnerTypeAttribute(string innerType) : Attribute
+{
+ ///
+ /// Коллекция названий обработчиков, которые должны быть выполнены до этого оброботчика.
+ ///
+ public string InnerType { get; init; } = innerType;
+}
diff --git a/Pf2eDataScrapper/App/ProcessorCollection.cs b/Pf2eDataScrapper/App/ProcessorCollection.cs
new file mode 100644
index 0000000..ffea206
--- /dev/null
+++ b/Pf2eDataScrapper/App/ProcessorCollection.cs
@@ -0,0 +1,229 @@
+using System.ComponentModel;
+using System.Reflection;
+using Pf2eDataScrapper.Processors;
+
+namespace Pf2eDataScrapper.App;
+
+///
+/// Класс с коллекцией обработчиков.
+///
+internal class ProcessorCollection
+{
+ ///
+ /// Коллекция всех доступных обработчиков.
+ ///
+ public ICollection AllItems { get; } = [];
+
+ ///
+ /// Коллекция обработчиков, которые будут обрабатываться.
+ /// Для изменения необходимо использовать .
+ ///
+ public List Items { get; private set; } = [];
+
+ ///
+ /// Конструктор класса .
+ ///
+ public ProcessorCollection()
+ {
+ Assembly assembly = Assembly.GetExecutingAssembly();
+
+ foreach (Type type in assembly.GetTypes())
+ {
+ if (type.GetCustomAttributes(typeof(ProcessAttribute), true).Length <= 0)
+ {
+ continue;
+ }
+
+ AllItems.Add(CreateItem(type));
+ }
+
+ CheckDependencies();
+ FilterProcessors([]);
+ }
+
+ ///
+ /// Создание элемента коллекции обработчиков.
+ ///
+ /// Тип обработчика.
+ ///
+ private ProcessorCollectionItem CreateItem(Type type)
+ {
+ if (!type.IsSubclassOf(typeof(IProcessor)))
+ {
+ throw new(
+ $"'ProcessAttribute' attribute should only be applied to children of 'IProcessor' class. '{type.FullName}' is not."
+ );
+ }
+
+ ProcessAttribute processAttribute = type.GetCustomAttribute()!;
+ DescriptionAttribute? descriptionAttribute =
+ type.GetCustomAttribute();
+ ProcessorGroupAttribute? groupAttribute =
+ type.GetCustomAttribute();
+ ProcessorDependenciesAttribute? dependenciesAttribute =
+ type.GetCustomAttribute();
+ ProcessorInnerTypeAttribute? innerTypeAttribute =
+ type.GetCustomAttribute();
+
+ bool isCollection = innerTypeAttribute is not null;
+
+ ConstructorInfo? constructor = isCollection
+ ? type.GetConstructor([])
+ : type.GetConstructor([typeof(ProcessorInput)])!;
+
+ if (constructor is null)
+ {
+ throw new($"Не удаётся определить конструктор класса {type}");
+ }
+
+ return new()
+ {
+ Name = processAttribute.Name,
+ Type = type,
+ Description = descriptionAttribute?.Description ?? processAttribute.Name,
+ Group = groupAttribute?.Group ?? ProcessorGroupEnum.General,
+ Dependencies = dependenciesAttribute?.Dependencies ?? [],
+ IsCollectionProcessor = isCollection,
+ InnerType = innerTypeAttribute?.InnerType,
+ Constructor = constructor,
+ };
+ }
+
+ ///
+ /// Проверка, что все зависимости всех обработчиков могут быть удовлетворены.
+ ///
+ private void CheckDependencies()
+ {
+ foreach (ProcessorCollectionItem item in Items)
+ {
+ foreach (string dependency in item.Dependencies)
+ {
+ if (Items.All(i => i.Name != dependency))
+ {
+ throw new($"Dependency '{dependency}' for processor '{item.Name}' not found.");
+ }
+ }
+ }
+ }
+
+ ///
+ /// Сортировать обработчики в соответсвии со всеми зависимостями.
+ ///
+ public void SortItems()
+ {
+ Dictionary priorities = [];
+
+ while (priorities.Count < Items.Count)
+ {
+ foreach (ProcessorCollectionItem item in Items)
+ {
+ if (item.Priority > 0)
+ {
+ continue;
+ }
+
+ IEnumerable dependencyPriorities = item.Dependencies.Select(d =>
+ priorities.GetValueOrDefault(d, -1)
+ );
+
+ if (dependencyPriorities.Any(p => p == -1))
+ {
+ continue;
+ }
+
+ item.Priority = dependencyPriorities.Any() ? dependencyPriorities.Max() + 1 : 1;
+ priorities.Add(item.Name, item.Priority);
+ }
+ }
+
+ Items.Sort((a, b) => a.Priority - b.Priority);
+ }
+
+ ///
+ /// Ограничить список используемых обработчиков по названию.
+ /// Автоматически включает все обработчики, от которых зависят указанные в аргументе обработчики.
+ ///
+ /// Коллекция названиий требуемых обработчиков.
+ public void FilterProcessors(ICollection processorNames)
+ {
+ if (processorNames.Count == 0)
+ {
+ Items = [.. AllItems];
+ SortItems();
+ return;
+ }
+
+ Dictionary nameFlags = processorNames.ToDictionary(name => name, _ => false);
+
+ while (nameFlags.Values.Any(v => !v))
+ {
+ foreach (
+ KeyValuePair pair in nameFlags.Where(pair => !pair.Value).ToList()
+ )
+ {
+ ProcessorCollectionItem item = AllItems.First(item => item.Name == pair.Key);
+
+ foreach (string dependency in item.Dependencies)
+ {
+ nameFlags.TryAdd(dependency, false);
+ }
+
+ nameFlags[pair.Key] = true;
+ }
+ }
+
+ Items = AllItems.Where(item => nameFlags.ContainsKey(item.Name)).ToList();
+ }
+}
+
+///
+/// Элемент коллекции обработчиков.
+///
+internal class ProcessorCollectionItem
+{
+ ///
+ /// Название обработчика.
+ ///
+ public required string Name { get; init; }
+
+ ///
+ /// Тип класса обработчика.
+ ///
+ public required Type Type { get; init; }
+
+ ///
+ /// Описание обработчика.
+ ///
+ public string Description { get; init; } = "";
+
+ ///
+ /// Группа обработчика.
+ ///
+ public required ProcessorGroupEnum Group { get; init; }
+
+ ///
+ /// Коллекция названий обработчиков, после которых должен выполняться обработчик.
+ ///
+ public ICollection Dependencies { get; init; } = [];
+
+ ///
+ /// Приоритет выполнения обработчика.
+ ///
+ public int Priority { get; set; } = -1;
+
+ ///
+ /// Флаг, указывающий, обрабатывает ли обработчик коллекцию элементов.
+ /// Внутренний тип элементов указывается в .
+ ///
+ public required bool IsCollectionProcessor { get; init; }
+
+ ///
+ /// Флаг, указывающий внутренний тип коллекции обрабатываемых элементов.
+ ///
+ public string? InnerType { get; init; }
+
+ ///
+ /// Конструктор обработчика.
+ ///
+ public required ConstructorInfo Constructor { get; init; }
+}
diff --git a/Pf2eDataScrapper/App/ProcessorGroupEnum.cs b/Pf2eDataScrapper/App/ProcessorGroupEnum.cs
new file mode 100644
index 0000000..09d40ac
--- /dev/null
+++ b/Pf2eDataScrapper/App/ProcessorGroupEnum.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel;
+
+namespace Pf2eDataScrapper.App;
+
+public enum ProcessorGroupEnum
+{
+ [Description("Общие процессоры")]
+ General,
+
+ [Description("Архивы Нефиса: Подготовка")]
+ AonprdPreparation,
+
+ [Description("Архивы Нефиса: Основные сущности")]
+ AonprdEntities,
+
+ [Description("Архивы Нефиса: Подклассы")]
+ AonprdSubclasses,
+
+ [Description("Foundry EN: Подготовка")]
+ FoundryEnPreparation,
+}
diff --git a/Pf2eDataScrapper/ApplicationSettings.cs b/Pf2eDataScrapper/ApplicationSettings.cs
new file mode 100644
index 0000000..48a80a7
--- /dev/null
+++ b/Pf2eDataScrapper/ApplicationSettings.cs
@@ -0,0 +1,80 @@
+using System.ComponentModel;
+using dotenv.net;
+using dotenv.net.Utilities;
+
+namespace Pf2eDataScrapper;
+
+///
+/// Настройки программы.
+///
+internal class ApplicationSettings
+{
+ ///
+ /// Конструктор класса .
+ ///
+ public ApplicationSettings()
+ {
+ DotEnv.Load();
+ }
+
+ #region Настройки из .env
+
+ ///
+ /// Путь к папке с входными данными.
+ ///
+ [Browsable(true)]
+ [ReadOnly(true)]
+ [DisplayName("Путь к папке с входными данными.")]
+ [Description("Редактирование через .env-файл.")]
+ public string DataDirPath { get; } = EnvReader.GetStringValue("DATA_DIR");
+
+ ///
+ /// Папка в входными данными.
+ ///
+ [Browsable(false)]
+ public DirectoryInfo DataDir => new(DataDirPath);
+
+ ///
+ /// Путь к папке для сохранения результатов.
+ ///
+ [Browsable(true)]
+ [ReadOnly(true)]
+ [DisplayName("Путь к папке для сохранения результатов.")]
+ [Description("Редактирование через .env-файл.")]
+ public string OutputDirPath { get; } = EnvReader.GetStringValue("OUTPUT_DIR");
+
+ ///
+ /// Папка для сохранения результатов.
+ ///
+ [Browsable(false)]
+ public string OutputDir => new(OutputDirPath);
+
+ ///
+ /// Строка подключения к базе данных.
+ ///
+ [Browsable(true)]
+ [ReadOnly(true)]
+ [DisplayName("Строка подключения к базе данных.")]
+ [Description("Редактирование через .env-файл.")]
+ public string DatabaseConnection { get; } = EnvReader.GetStringValue("DATABASE_CONNECTION");
+
+ #endregion
+
+ #region Основные настройки
+
+ ///
+ /// Флаг, указывающий, что все старые записи необходимо удалить.
+ ///
+ [Browsable(true)]
+ [DisplayName("Удаление всех записей перед запуском.")]
+ [Description("Редактирование через .env-файл.")]
+ public bool TruncateAllTables { get; set; } = true;
+
+ ///
+ /// Список обработчиков, которые должны быть выполнены.
+ /// Пустой список означает, что должны быть выполнены все обработчики.
+ ///
+ public ICollection ProcessorNames { get; } = new List();
+
+ #endregion
+}
diff --git a/Pf2eDataScrapper/Forms/StartForm.Designer.cs b/Pf2eDataScrapper/Forms/StartForm.Designer.cs
new file mode 100644
index 0000000..387245b
--- /dev/null
+++ b/Pf2eDataScrapper/Forms/StartForm.Designer.cs
@@ -0,0 +1,166 @@
+namespace Pf2eDataScrapper.Forms;
+
+partial class StartForm
+{
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ MainSplitContainer = new SplitContainer();
+ PropertiesGroupBox = new GroupBox();
+ SettingsPropertyGrid = new PropertyGrid();
+ StartButton = new Button();
+ ProcessorsGroupBox = new GroupBox();
+ DeselectAllButton = new Button();
+ SelectAllButton = new Button();
+ ProcessorsListView = new ListView();
+ ((System.ComponentModel.ISupportInitialize)MainSplitContainer).BeginInit();
+ MainSplitContainer.Panel1.SuspendLayout();
+ MainSplitContainer.Panel2.SuspendLayout();
+ MainSplitContainer.SuspendLayout();
+ PropertiesGroupBox.SuspendLayout();
+ ProcessorsGroupBox.SuspendLayout();
+ SuspendLayout();
+ //
+ // MainSplitContainer
+ //
+ MainSplitContainer.Dock = DockStyle.Fill;
+ MainSplitContainer.Location = new Point(0, 0);
+ MainSplitContainer.Name = "MainSplitContainer";
+ //
+ // MainSplitContainer.Panel1
+ //
+ MainSplitContainer.Panel1.Controls.Add(PropertiesGroupBox);
+ MainSplitContainer.Panel1MinSize = 300;
+ //
+ // MainSplitContainer.Panel2
+ //
+ MainSplitContainer.Panel2.Controls.Add(ProcessorsGroupBox);
+ MainSplitContainer.Panel2.Controls.Add(StartButton);
+ MainSplitContainer.Panel2MinSize = 300;
+ MainSplitContainer.Size = new Size(931, 677);
+ MainSplitContainer.SplitterDistance = 300;
+ MainSplitContainer.TabIndex = 0;
+ //
+ // PropertiesGroupBox
+ //
+ PropertiesGroupBox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
+ PropertiesGroupBox.Controls.Add(SettingsPropertyGrid);
+ PropertiesGroupBox.Location = new Point(3, 3);
+ PropertiesGroupBox.Name = "PropertiesGroupBox";
+ PropertiesGroupBox.Size = new Size(294, 671);
+ PropertiesGroupBox.TabIndex = 0;
+ PropertiesGroupBox.TabStop = false;
+ PropertiesGroupBox.Text = "Свойства";
+ //
+ // SettingsPropertyGrid
+ //
+ SettingsPropertyGrid.BackColor = SystemColors.Control;
+ SettingsPropertyGrid.Dock = DockStyle.Fill;
+ SettingsPropertyGrid.Location = new Point(3, 19);
+ SettingsPropertyGrid.Name = "SettingsPropertyGrid";
+ SettingsPropertyGrid.Size = new Size(288, 649);
+ SettingsPropertyGrid.TabIndex = 0;
+ //
+ // StartButton
+ //
+ StartButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
+ StartButton.Font = new Font("Segoe UI", 18F, FontStyle.Bold);
+ StartButton.Location = new Point(3, 611);
+ StartButton.Name = "StartButton";
+ StartButton.Size = new Size(621, 63);
+ StartButton.TabIndex = 0;
+ StartButton.Text = "Запуск";
+ StartButton.UseVisualStyleBackColor = true;
+ //
+ // ProcessorsGroupBox
+ //
+ ProcessorsGroupBox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
+ ProcessorsGroupBox.Controls.Add(ProcessorsListView);
+ ProcessorsGroupBox.Controls.Add(SelectAllButton);
+ ProcessorsGroupBox.Controls.Add(DeselectAllButton);
+ ProcessorsGroupBox.Location = new Point(3, 3);
+ ProcessorsGroupBox.Name = "ProcessorsGroupBox";
+ ProcessorsGroupBox.Size = new Size(621, 602);
+ ProcessorsGroupBox.TabIndex = 1;
+ ProcessorsGroupBox.TabStop = false;
+ ProcessorsGroupBox.Text = "Обработчики";
+ //
+ // DeselectAllButton
+ //
+ DeselectAllButton.Location = new Point(6, 19);
+ DeselectAllButton.Name = "DeselectAllButton";
+ DeselectAllButton.Size = new Size(137, 23);
+ DeselectAllButton.TabIndex = 0;
+ DeselectAllButton.Text = "Снять выделение всех";
+ DeselectAllButton.UseVisualStyleBackColor = true;
+ //
+ // SelectAllButton
+ //
+ SelectAllButton.Location = new Point(149, 19);
+ SelectAllButton.Name = "SelectAllButton";
+ SelectAllButton.Size = new Size(137, 23);
+ SelectAllButton.TabIndex = 1;
+ SelectAllButton.Text = "Выделить все";
+ SelectAllButton.UseVisualStyleBackColor = true;
+ //
+ // ProcessorsListView
+ //
+ ProcessorsListView.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
+ ProcessorsListView.CheckBoxes = true;
+ ProcessorsListView.Location = new Point(6, 48);
+ ProcessorsListView.Name = "ProcessorsListView";
+ ProcessorsListView.Size = new Size(606, 548);
+ ProcessorsListView.TabIndex = 2;
+ ProcessorsListView.UseCompatibleStateImageBehavior = false;
+ //
+ // StartForm
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(931, 677);
+ Controls.Add(MainSplitContainer);
+ Name = "StartForm";
+ Text = "Настройки импорта данных";
+ MainSplitContainer.Panel1.ResumeLayout(false);
+ MainSplitContainer.Panel2.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)MainSplitContainer).EndInit();
+ MainSplitContainer.ResumeLayout(false);
+ PropertiesGroupBox.ResumeLayout(false);
+ ProcessorsGroupBox.ResumeLayout(false);
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private SplitContainer MainSplitContainer;
+ private GroupBox PropertiesGroupBox;
+ private PropertyGrid SettingsPropertyGrid;
+ private Button StartButton;
+ private GroupBox ProcessorsGroupBox;
+ private Button SelectAllButton;
+ private Button DeselectAllButton;
+ private ListView ProcessorsListView;
+}
\ No newline at end of file
diff --git a/Pf2eDataScrapper/Forms/StartForm.cs b/Pf2eDataScrapper/Forms/StartForm.cs
new file mode 100644
index 0000000..70bbf4d
--- /dev/null
+++ b/Pf2eDataScrapper/Forms/StartForm.cs
@@ -0,0 +1,9 @@
+namespace Pf2eDataScrapper.Forms;
+
+public partial class StartForm : Form
+{
+ public StartForm()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/Pf2eDataScrapper/Forms/StartForm.resx b/Pf2eDataScrapper/Forms/StartForm.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/Pf2eDataScrapper/Forms/StartForm.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Pf2eDataScrapper/ImportApplication.cs b/Pf2eDataScrapper/ImportApplication.cs
new file mode 100644
index 0000000..18cf2ee
--- /dev/null
+++ b/Pf2eDataScrapper/ImportApplication.cs
@@ -0,0 +1,58 @@
+using Microsoft.Extensions.DependencyInjection;
+using Pf2eDataScrapper.App;
+using Pf2eDataScrapper.Forms;
+using Pf2eModel;
+
+namespace Pf2eDataScrapper;
+
+internal sealed class ImportApplication : ApplicationContext
+{
+ public ImportApplication()
+ {
+ InitializeServices();
+ CreateStartForm();
+ }
+
+ #region "Внедрение зависимостей (DI)"
+
+ public IServiceCollection Services = new ServiceCollection();
+
+ private void InitializeServices()
+ {
+ Services.AddSingleton(this);
+ Services.AddSingleton(Settings);
+
+ Services.AddSingleton();
+
+ Services.AddDbContext();
+ }
+
+ #endregion
+
+ #region "Настройки"
+
+ public ApplicationSettings Settings = new();
+
+ #endregion
+
+ #region "Формы"
+
+ private StartForm? _startForm;
+
+ #endregion
+
+ #region "Жизненный цикл"
+
+ private void CreateStartForm()
+ {
+ _startForm = new() { StartPosition = FormStartPosition.CenterParent };
+ _startForm.Show();
+ }
+
+ private void StartProcess()
+ {
+ _startForm!.Close();
+ }
+
+ #endregion
+}
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdDataBuilder.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdDataBuilder.cs
index 9fb3ca6..ae02027 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdDataBuilder.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdDataBuilder.cs
@@ -2,6 +2,7 @@
using Newtonsoft.Json.Linq;
using Pf2eDataScrapper.Importers.Implementations.Aonprd.Compendium;
using Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors;
+using Pf2eDataScrapper.Processors;
using Pf2eModel;
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder;
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorAttribute.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorAttribute.cs
index faac790..301d742 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorAttribute.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorAttribute.cs
@@ -1,43 +1,22 @@
-namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder;
+using Pf2eDataScrapper.App.Attributes;
+
+namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder;
///
/// Атрибут обработчика данных Архивов Нефиса.
///
-/// Название обработчика.
-/// Тип данных, которые обработчик обрабатывает.
-/// Названия обработчиков, которые должны быть выполнены до запуска этого обработчика.
-/// Флаг, указывающий, следует ли добавить важные общие зависимости для обработчка.
[AttributeUsage(AttributeTargets.Class)]
-public class AonprdProcessorAttribute(
- string name,
- string? type,
- string[] dependencies,
- bool includeDefaults = true
-) : Attribute
+public class AonprdProcessorAttribute : Attributes
{
///
/// Важные общие зависимости для обработчка.
///
- private static readonly string[] DefaultDependencies = ["trait", "source"];
-
- ///
- /// Название обработчика.
- ///
- public readonly string Name = name;
+ private static readonly string[] DefaultDependencies = ["aonprd:trait", "aonprd:source"];
///
/// Тип данных, которые обработчик обрабатывает.
///
- public readonly string? Type = type;
-
- ///
- /// Названия обработчиков, которые должны быть выполнены до запуска этого обработчика.
- ///
- public readonly IEnumerable Dependencies =
- [
- .. includeDefaults ? DefaultDependencies : [],
- .. dependencies,
- ];
+ public string Type { get; init; }
///
/// Конструктор класса со стандартными общими зависимости для обработчка.
@@ -62,4 +41,22 @@ public class AonprdProcessorAttribute(
/// Тип данных, которые обработчик обрабатывает.
public AonprdProcessorAttribute(string name, string type)
: this(name, type, DefaultDependencies) { }
+
+ ///
+ /// Основной конструктор класса .
+ ///
+ /// Название обработчика.
+ /// Тип данных, которые обработчик обрабатывает.
+ /// Названия обработчиков, которые должны быть выполнены до запуска этого обработчика.
+ /// Флаг, указывающий, следует ли добавить важные общие зависимости для обработчка.
+ public AonprdProcessorAttribute(
+ string name,
+ string? type,
+ ICollection dependencies,
+ bool includeDefaults = true
+ )
+ : base($"aonprd:{name}", [.. includeDefaults ? DefaultDependencies : [], .. dependencies])
+ {
+ Type = type;
+ }
}
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorCollection.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorCollection.cs
index 9d66d8a..4ec1ccf 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorCollection.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorCollection.cs
@@ -1,5 +1,5 @@
using System.Reflection;
-using Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors;
+using Pf2eDataScrapper.Processors;
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder;
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorInput.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorInput.cs
index d369fec..d2fde33 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorInput.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorInput.cs
@@ -1,5 +1,6 @@
using Newtonsoft.Json.Linq;
using Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Helpers;
+using Pf2eDataScrapper.Processors;
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder;
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AbstractEntityProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AbstractEntityProcessor.cs
index 7876221..03f14a5 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AbstractEntityProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AbstractEntityProcessor.cs
@@ -3,6 +3,7 @@ using System.Text;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using Pf2eDataScrapper.Processors;
using Pf2eModel;
using Pf2eModel.Model;
using Pf2eModel.Model.Base;
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AbstractProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AbstractProcessor.cs
deleted file mode 100644
index 2129587..0000000
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AbstractProcessor.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Helpers;
-using Pf2eModel;
-
-namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors;
-
-///
-/// Абстрактный класс-обработчик данных, полученных из Архивов Нефиса.
-/// Класс предназначен для обработки данных с помощью различных обработчиков,
-/// для которых указан атрибут .
-///
-/// Объект обработки вводимого JSON.
-///
-internal abstract class AbstractProcessor(AonprdProcessorInput input)
-{
- ///
- /// Вспомогательный класс для работы с базой данных.
- ///
- protected readonly DatabaseHelper Helper = DatabaseHelper.Instance;
-
- ///
- /// Вспомогательный класс для работы со строками и форматированием.
- ///
- protected readonly StringHelper StringHelper = StringHelper.Instance;
-
- ///
- /// Вспомогательный класс для работы с глобальными настройками.
- ///
- protected readonly AonprdBuilderGlobals Globals = AonprdBuilderGlobals.Instance;
-
- ///
- /// Контекст базы данных для работы с данными.
- ///
- public readonly Pf2eDbContext Context = DatabaseHelper.DbContext;
-
- ///
- /// Объект обработки вводимого JSON.
- ///
- public readonly AonprdProcessorInput Input = input;
-
- ///
- /// Основной метод обработки данных.
- ///
- public abstract void Process();
-
- ///
- /// Метод для сохранения изменений в базе данных.
- ///
- public abstract void Save();
-}
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/ExternalProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/ExternalProcessor.cs
index fd688fc..18508df 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/ExternalProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/ExternalProcessor.cs
@@ -1,4 +1,5 @@
-using Pf2eModel.Model.Base.Targets;
+using Pf2eDataScrapper.Processors;
+using Pf2eModel.Model.Base.Targets;
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Common;
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/SkillProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/SkillProcessor.cs
index 26ab2ed..f0b6ef4 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/SkillProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/SkillProcessor.cs
@@ -1,4 +1,5 @@
-using Pf2eModel.Model.Common;
+using Pf2eDataScrapper.Processors;
+using Pf2eModel.Model.Common;
using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum;
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/SourceProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/SourceProcessor.cs
index 8f0a417..1cd6a68 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/SourceProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Common/SourceProcessor.cs
@@ -1,4 +1,5 @@
-using Pf2eModel.Model.Base.Source;
+using Pf2eDataScrapper.Processors;
+using Pf2eModel.Model.Base.Source;
using Pf2eModel.Model.Enum;
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Common;
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/FeatProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/FeatProcessor.cs
index aa93139..c863398 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/FeatProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/FeatProcessor.cs
@@ -53,7 +53,7 @@ internal class FeatProcessor(AonprdProcessorInput input) : AbstractEntityProcess
Archetype[] archetypes = Context
// ReSharper disable once EntityFramework.UnsupportedServerSideFunctionCall
.Archetypes.Where(a => Pf2eDbContext.LocaleSearchArray(a.Entity.Name, archetypeStrings))
- // .Where(a => archetypeStrings.Contains(a.Entity.Name.ToString()))
+ // .Where(a => archetypeStrings.Contains(a.Entity.Group.ToString()))
.ToArray();
if (archetypes.Length != 0)
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/Rules/RulesOrderProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/Rules/RulesOrderProcessor.cs
index 98c23d3..9d673e3 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/Rules/RulesOrderProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/Rules/RulesOrderProcessor.cs
@@ -6,6 +6,7 @@
// Ну а пока просто расставляем родительские и дочерние элементы.
using System.Data;
+using Pf2eDataScrapper.Processors;
using Pf2eModel.Model.Structure;
using Rule = Pf2eModel.Model.Structure.Rule;
diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/Rules/RulesTocProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/Rules/RulesTocProcessor.cs
index 511d4a4..5d76d93 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/Rules/RulesTocProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/Types/Rules/RulesTocProcessor.cs
@@ -2,6 +2,7 @@
using System.Web;
using AngleSharp;
using AngleSharp.Dom;
+using Pf2eDataScrapper.Processors;
using Pf2eModel.Model.Base.Source;
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Types.Rules;
diff --git a/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/Compendium/CompendiumFolder.cs b/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/Compendium/CompendiumFolder.cs
index 07557b5..e51fe04 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/Compendium/CompendiumFolder.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/Compendium/CompendiumFolder.cs
@@ -83,6 +83,6 @@ internal class CompendiumFolder
/// Строковое представление данных о папки компендиума.
public override string ToString()
{
- return $"CompendiumFolder([Id={Id}][Type={Type}][Name={Name}][Path={Path}][Parent={Parent?.Name ?? "null"}])";
+ return $"CompendiumFolder([Id={Id}][Type={Type}][Group={Name}][Path={Path}][Parent={Parent?.Name ?? "null"}])";
}
}
diff --git a/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/AbstractProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/AbstractProcessor.cs
index 8ff9468..80b7cc3 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/AbstractProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/AbstractProcessor.cs
@@ -2,6 +2,7 @@
using System.Text;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json.Linq;
+using Pf2eDataScrapper.Processors;
using Pf2eModel;
using Pf2eModel.Model;
using Pf2eModel.Model.Base;
@@ -51,7 +52,7 @@ internal abstract class AbstractProcessor(ProcessorInput input)
EntityAlias alias = new()
{
Type = LocaleType.English,
- Alias = Entity.Name,
+ Alias = Entity.Group,
EntityId = Entity.Id,
Entity = Entity
};
@@ -147,13 +148,13 @@ internal abstract class AbstractProcessor(ProcessorInput input)
/*
foreach (string name in names)
{
- if (result.Any(t => t.Entity.Name.Contains(name)))
+ if (result.Any(t => t.Entity.Group.Contains(name)))
{
continue;
}
Trait trait = new()
{
- Name = name,
+ Group = name,
Slug = name,
Type = TraitType.Regular,
Description = "",
diff --git a/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/PF2eFoundryDataBuilder.cs b/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/PF2eFoundryDataBuilder.cs
index cd88174..16ca5e1 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/PF2eFoundryDataBuilder.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/PF2eFoundryDataBuilder.cs
@@ -2,6 +2,7 @@
using Konsole;
using Newtonsoft.Json.Linq;
using Pf2eDataScrapper.Importers.Implementations.Pf2eFoundry.Compendium;
+using Pf2eDataScrapper.Processors;
using Pf2eModel;
namespace Pf2eDataScrapper.Importers.Implementations.Pf2eFoundry.DataBuilder;
diff --git a/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/Processors/ActionProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/Processors/ActionProcessor.cs
index b17f9b2..5e0d2b5 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/Processors/ActionProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/Processors/ActionProcessor.cs
@@ -1,4 +1,5 @@
using Newtonsoft.Json.Linq;
+using Pf2eDataScrapper.Processors;
using Pf2eModel.Model.Enum;
namespace Pf2eDataScrapper.Importers.Implementations.Pf2eFoundry.DataBuilder.Processors;
diff --git a/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/Processors/ConditionProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/Processors/ConditionProcessor.cs
index f549256..acb7ca1 100644
--- a/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/Processors/ConditionProcessor.cs
+++ b/Pf2eDataScrapper/Importers/Implementations/Pf2eFoundry/DataBuilder/Processors/ConditionProcessor.cs
@@ -1,4 +1,5 @@
using Newtonsoft.Json.Linq;
+using Pf2eDataScrapper.Processors;
using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure;
diff --git a/Pf2eDataScrapper/Pf2eDataScrapper.csproj b/Pf2eDataScrapper/Pf2eDataScrapper.csproj
index a61becb..504d388 100644
--- a/Pf2eDataScrapper/Pf2eDataScrapper.csproj
+++ b/Pf2eDataScrapper/Pf2eDataScrapper.csproj
@@ -1,10 +1,10 @@
- 13.0
- Exe
- net9.0
- enable
+ WinExe
+ net9.0-windows7.0
enable
+ true
+ enable
diff --git a/Pf2eDataScrapper/Processors/AbstractInputProcessor.cs b/Pf2eDataScrapper/Processors/AbstractInputProcessor.cs
new file mode 100644
index 0000000..a576ae2
--- /dev/null
+++ b/Pf2eDataScrapper/Processors/AbstractInputProcessor.cs
@@ -0,0 +1,44 @@
+using Microsoft.Extensions.DependencyInjection;
+using Pf2eDataScrapper.App;
+using Pf2eModel;
+
+namespace Pf2eDataScrapper.Processors;
+
+///
+/// Абстрактный класс-обработчик данных, полученных из Архивов Нефиса.
+/// Класс предназначен для обработки данных с помощью различных обработчиков,
+/// для которых указан атрибут .
+///
+/// Провайдер сервисов.
+/// Провайдер сервисов.
+///
+internal abstract class AbstractInputProcessor(
+ IServiceProvider serviceProvider,
+ ProcessorInput input
+) : IProcessor
+{
+ ///
+ /// Провайдер сервисов.
+ ///
+ public IServiceProvider ServiceProvider { get; } = serviceProvider;
+
+ ///
+ /// Контекст базы данных.
+ ///
+ public Pf2eDbContext Context { get; } = serviceProvider.GetService()!;
+
+ ///
+ /// Ввод.
+ ///
+ public ProcessorInput Input { get; } = input;
+
+ ///
+ /// Основной метод обработки данных.
+ ///
+ public abstract void Process();
+
+ ///
+ /// Метод для сохранения изменений в базе данных.
+ ///
+ public abstract void Save();
+}
diff --git a/Pf2eDataScrapper/Processors/AbstractProcessor.cs b/Pf2eDataScrapper/Processors/AbstractProcessor.cs
new file mode 100644
index 0000000..155a670
--- /dev/null
+++ b/Pf2eDataScrapper/Processors/AbstractProcessor.cs
@@ -0,0 +1,35 @@
+using Microsoft.Extensions.DependencyInjection;
+using Pf2eDataScrapper.App;
+using Pf2eModel;
+
+namespace Pf2eDataScrapper.Processors;
+
+///
+/// Абстрактный класс-обработчик данных, полученных из Архивов Нефиса.
+/// Класс предназначен для обработки данных с помощью различных обработчиков,
+/// для которых указан атрибут .
+///
+/// Провайдер сервисов.
+///
+internal abstract class AbstractProcessor(IServiceProvider serviceProvider) : IProcessor
+{
+ ///
+ /// Провайдер сервисов.
+ ///
+ public IServiceProvider ServiceProvider { get; } = serviceProvider;
+
+ ///
+ /// Контекст базы данных.
+ ///
+ public Pf2eDbContext Context { get; } = serviceProvider.GetService()!;
+
+ ///
+ /// Основной метод обработки данных.
+ ///
+ public abstract void Process();
+
+ ///
+ /// Метод для сохранения изменений в базе данных.
+ ///
+ public abstract void Save();
+}
diff --git a/Pf2eDataScrapper/Processors/IProcessor.cs b/Pf2eDataScrapper/Processors/IProcessor.cs
new file mode 100644
index 0000000..33849eb
--- /dev/null
+++ b/Pf2eDataScrapper/Processors/IProcessor.cs
@@ -0,0 +1,21 @@
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Pf2eDataScrapper.Processors;
+
+public interface IProcessor
+{
+ ///
+ /// Провайдер сервисов.
+ ///
+ IServiceProvider ServiceProvider { get; }
+
+ ///
+ /// Основной метод обработки данных.
+ ///
+ void Process();
+
+ ///
+ /// Метод для сохранения изменений в базе данных.
+ ///
+ void Save();
+}
diff --git a/Pf2eDataScrapper/Importers/ProcessorInput.cs b/Pf2eDataScrapper/Processors/ProcessorInput.cs
similarity index 99%
rename from Pf2eDataScrapper/Importers/ProcessorInput.cs
rename to Pf2eDataScrapper/Processors/ProcessorInput.cs
index 85081e7..cb683be 100644
--- a/Pf2eDataScrapper/Importers/ProcessorInput.cs
+++ b/Pf2eDataScrapper/Processors/ProcessorInput.cs
@@ -2,7 +2,7 @@
using NpgsqlTypes;
using Pf2eModel.Model.Common.I18n;
-namespace Pf2eDataScrapper.Importers;
+namespace Pf2eDataScrapper.Processors;
///
/// Класс для работы с JSON-объектом.
diff --git a/Pf2eDataScrapper/Program.cs b/Pf2eDataScrapper/Program.cs
index d32ba97..328179e 100644
--- a/Pf2eDataScrapper/Program.cs
+++ b/Pf2eDataScrapper/Program.cs
@@ -1,18 +1,23 @@
-using Pf2eDataScrapper;
-using Pf2eDataScrapper.Importers.Implementations.Aonprd;
+namespace Pf2eDataScrapper;
-// Console.SetWindowSize(Console.LargestWindowWidth - 20, Console.LargestWindowHeight - 10);
+internal static class Program
+{
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ ApplicationConfiguration.Initialize();
-EnvSettings.Load();
+ Application.SetHighDpiMode(HighDpiMode.SystemAware);
-/*
-Pf2EFoundryImporter importer = new();
-*/
+#pragma warning disable WFO5001
+ Application.SetColorMode(SystemColorMode.System);
+#pragma warning restore WFO5001
-AonprdImporter importer = new();
-
-// importer.ProcessorNames = ["rules", "rules-order"];
-
-importer.Prepare();
-importer.Import();
-// importer.BuildSchemas();
+ Application.Run(new ImportApplication());
+ }
+}
diff --git a/Pf2eViewer/Pf2eViewer.csproj b/Pf2eViewer/Pf2eViewer.csproj
index d479e08..973136e 100644
--- a/Pf2eViewer/Pf2eViewer.csproj
+++ b/Pf2eViewer/Pf2eViewer.csproj
@@ -26,7 +26,4 @@
Settings.Designer.cs
-
-
-