Глобальный рефакторинг пространств имён
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Compendium;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd;
|
||||
|
||||
using StringHelper = Helpers.StringHelper;
|
||||
|
||||
/// <summary>
|
||||
/// Класс обработки данных с сайта Архивов Нефеса.
|
||||
/// </summary>
|
||||
internal class AonprdImporter : AbstractImporter
|
||||
{
|
||||
/// <summary>
|
||||
/// Название внешней ссылки.
|
||||
/// </summary>
|
||||
public const string TargetName = "Archives of Nethys Pathfinder 2e";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Name => TargetName;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string Slug => "aonprd";
|
||||
|
||||
#region "Внедрение зависимостей"
|
||||
|
||||
public static void RegisterServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<AonprdImporter>();
|
||||
services.AddSingleton<AonprdRepository>();
|
||||
services.AddSingleton<AonprdCompendium>();
|
||||
|
||||
services.AddSingleton<AonprdBuilderGlobals>();
|
||||
services.AddSingleton<RuleTocCollection>();
|
||||
services.AddTransient<StringHelper>();
|
||||
|
||||
AonprdProcessorInputExtension.RegisterServices(services);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Repositories;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd;
|
||||
|
||||
/// <summary>
|
||||
/// Основной класс для работы с репозиторием данных Aonprd.
|
||||
/// </summary>
|
||||
internal class AonprdRepository(AonprdImporter importer) : AbstractImporterRepository(importer)
|
||||
{
|
||||
/// <summary>
|
||||
/// URL для доступа к API Aonprd.
|
||||
/// </summary>
|
||||
public const string SearchUrl = "https://elasticsearch.aonprd.com";
|
||||
|
||||
/// <summary>
|
||||
/// Текущая ревизия данных. Значение обновляется при обновлении репозитория.
|
||||
/// </summary>
|
||||
public int Revision { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Метод для загрузки данных из API Aonprd.
|
||||
/// </summary>
|
||||
private string Load(string url)
|
||||
{
|
||||
if (!url.StartsWith("http://") && !url.StartsWith("https://"))
|
||||
{
|
||||
url = SearchUrl + url;
|
||||
}
|
||||
|
||||
using HttpClient client = new();
|
||||
using Task<Stream> stream = client.GetStreamAsync(url);
|
||||
using StreamReader reader = new(stream.Result);
|
||||
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Update(ProcessProgress progress)
|
||||
{
|
||||
if (CheckRevision())
|
||||
{
|
||||
progress.Local.Complete();
|
||||
progress.Information($"Данные Aonprd актуальны, текущая ревизия {Revision}.");
|
||||
return;
|
||||
}
|
||||
|
||||
progress.Information(
|
||||
$"Данные Aonprd устарели, обновляем {RepositoryDirPath} до ревизии {Revision}..."
|
||||
);
|
||||
|
||||
progress.Local.Reset(1);
|
||||
|
||||
if (Directory.Exists(RepositoryDirPath))
|
||||
{
|
||||
Directory.Delete(RepositoryDirPath, true);
|
||||
}
|
||||
Directory.CreateDirectory(RepositoryDirPath);
|
||||
|
||||
WriteFile("revision.txt", Revision.ToString());
|
||||
|
||||
progress.Local.Start("Загрузка индекса...");
|
||||
|
||||
string indexContent = Load($"/json-data/aon{Revision}-index.json");
|
||||
WriteFile("index.json", indexContent);
|
||||
|
||||
JObject indexJson = JObject.Parse(indexContent);
|
||||
|
||||
progress.Local.Reset(indexJson.Count + 1);
|
||||
progress.Local.End();
|
||||
|
||||
foreach (KeyValuePair<string, JToken?> kvp in indexJson)
|
||||
{
|
||||
string fileName = kvp.Key;
|
||||
progress.Local.Start(fileName);
|
||||
|
||||
string fileContent = Load($"/json-data/{fileName}.json");
|
||||
WriteFile($"{fileName}.json", fileContent);
|
||||
|
||||
progress.Local.End();
|
||||
}
|
||||
|
||||
progress.Local.Complete();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверка актуальности данных.
|
||||
/// </summary>
|
||||
/// <returns>true - актуальная ревизия, false - устаревшая/отсутсвует.</returns>
|
||||
private bool CheckRevision()
|
||||
{
|
||||
JObject page = JObject.Parse(Load("/aon/_doc/feat-1"));
|
||||
|
||||
Revision = Convert.ToInt32(
|
||||
page.SelectToken("_index")?.ToObject<string>()?.Replace("aon", "")
|
||||
?? throw new("Не удаётся получить ревизию Архивов Нефиса.")
|
||||
);
|
||||
|
||||
string revisionFile = Path.Combine(RepositoryDirPath, "revision.txt");
|
||||
if (!File.Exists(revisionFile))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using StreamReader reader = new(revisionFile);
|
||||
string lastRevision = reader.ReadToEnd();
|
||||
return lastRevision == Revision.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Запись данных в файл.
|
||||
/// </summary>
|
||||
/// <param name="path">Путь к файлу.</param>
|
||||
/// <param name="content">Содержимое, которе требуется записать в файл.</param>
|
||||
private void WriteFile(string path, string content)
|
||||
{
|
||||
string filePath = Path.Combine(RepositoryDirPath, path);
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
using StreamWriter writer = new(filePath);
|
||||
writer.Write(content);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Compendium;
|
||||
|
||||
/// <summary>
|
||||
/// Класс хранения данных компендиума.
|
||||
/// </summary>
|
||||
internal sealed class AonprdCompendium(AonprdRepository repository) : AbstractCompendium
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override AonprdRepository Repository { get; } = repository;
|
||||
|
||||
/// <summary>
|
||||
/// Коллекция всех записей компендиума.
|
||||
/// </summary>
|
||||
public ConcurrentBag<AonprdCompendiumItem> Items { get; } = [];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int Count(params ICollection<string> types) =>
|
||||
types.Count == 0 ? Items.Count : Items.Count(i => types.Contains(i.Type));
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IEnumerable<Tuple<AbstractCompendiumItem, JObject>> Iterate(
|
||||
params ICollection<string> types
|
||||
)
|
||||
{
|
||||
IEnumerable<string> files =
|
||||
types.Count == 0
|
||||
? Items.Select(item => item.File).Distinct()
|
||||
: Items
|
||||
.Where(item => types.Contains(item.Type))
|
||||
.Select(item => item.File)
|
||||
.Distinct();
|
||||
|
||||
foreach (string file in files)
|
||||
{
|
||||
Dictionary<string, AonprdCompendiumItem> fileReferences = Items
|
||||
.Where(i => i.File == file)
|
||||
.ToDictionary(i => i.Id);
|
||||
|
||||
using StreamReader fileReader = new(
|
||||
Path.Combine(Repository.RepositoryDirPath, $"{file}.json")
|
||||
);
|
||||
JArray array = JArray.Parse(fileReader.ReadToEnd());
|
||||
|
||||
foreach (JToken item in array)
|
||||
{
|
||||
string? id = item.SelectToken("id")?.ToString();
|
||||
|
||||
if (
|
||||
id is null
|
||||
|| !fileReferences.TryGetValue(id, out AonprdCompendiumItem? reference)
|
||||
|| (types.Count > 0 && !types.Contains(reference.Type))
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return new(reference, (JObject)item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Compendium;
|
||||
|
||||
/// <summary>
|
||||
/// Ссылка на сущность с указанием файла, в котором она хранится.
|
||||
/// </summary>
|
||||
/// <param name="id">Идентификатор сущности.</param>
|
||||
/// <param name="file">Имя файла.</param>
|
||||
internal class AonprdCompendiumItem(string id, string file) : AbstractCompendiumItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Идентификатор сущности.
|
||||
/// </summary>
|
||||
public override string Id { get; } = id;
|
||||
|
||||
/// <summary>
|
||||
/// Тип сущности.
|
||||
/// </summary>
|
||||
public override string Type { get; } = ResolveType(id);
|
||||
|
||||
/// <summary>
|
||||
/// Имя файла, в котором хранится сущность.
|
||||
/// </summary>
|
||||
public string File { get; } = file;
|
||||
|
||||
/// <summary>
|
||||
/// Определение типа сущности как префикса идентификатора.
|
||||
/// </summary>
|
||||
public static string ResolveType(string id)
|
||||
{
|
||||
string type = string.Join('-', id.Split('-')[..^1]);
|
||||
|
||||
return SubType(type, "equipment") ?? SubType(type, "weapon") ?? type;
|
||||
|
||||
static string? SubType(string type, string cat)
|
||||
{
|
||||
return type.StartsWith($"{cat}-") && type != cat
|
||||
? type.EndsWith("-bonus")
|
||||
? $"{cat}-bonus"
|
||||
: $"{cat}-sub"
|
||||
: null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Database.Model.Base.Targets;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Класс-помощник, хранящий необходимые глобальные данные.
|
||||
/// </summary>
|
||||
internal class AonprdBuilderGlobals
|
||||
{
|
||||
/// <summary>
|
||||
/// Цель внешних ссылок Архивов Нефисов.
|
||||
/// </summary>
|
||||
public ExternalTarget AonprdTarget { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Словарь идентификаторов источников.
|
||||
/// </summary>
|
||||
public Dictionary<string, int> SourceIds { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Словарь идентификаторов признаков.
|
||||
/// </summary>
|
||||
public Dictionary<string, int> TraitIds { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Список идентификаторов сущностей, которые нужно игнорировать при обработке.
|
||||
/// </summary>
|
||||
public List<string> Ignore { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Словарей суффиксов для сущностей
|
||||
/// </summary>
|
||||
public Dictionary<string, string> SlugSuffixes { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Словарь допольнительных проверок связей.
|
||||
/// Ключ - устаревшая сущность, значение - обновлённая.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> LegacyRemasterExtra { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Словарь сущностей, которые нужно слить с другой/другими.
|
||||
/// Ключ - пропускаемая сущность. Значение - целевая сущность.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> MergeSources { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Словарь сущностей, которые нужно слить с другой/другими.
|
||||
/// Ключ - пропускаемая сущность. Значение - целевая сущность.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> SubclassGroups { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Конструктор класса <see cref="AonprdBuilderGlobals"/>.
|
||||
/// </summary>
|
||||
public AonprdBuilderGlobals()
|
||||
{
|
||||
using StreamReader fileReader = new("Resources\\ImportAdaptation.json");
|
||||
|
||||
JObject? json = JObject
|
||||
.Parse(fileReader.ReadToEnd())
|
||||
.SelectToken("Aonprd")
|
||||
?.ToObject<JObject>();
|
||||
|
||||
if (json is not null)
|
||||
{
|
||||
Ignore = json.SelectToken("Ignore")?.ToObject<List<string>>() ?? [];
|
||||
|
||||
SlugSuffixes = JsonToDictionary(json, "SlugSuffixes");
|
||||
LegacyRemasterExtra = JsonToDictionary(json, "LegacyRemasterExtra");
|
||||
MergeSources = JsonToDictionary(json, "MergeSources");
|
||||
SubclassGroups = JsonToDictionary(json, "SubclassGroups");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить суффикс для ссылки.
|
||||
/// </summary>
|
||||
/// <param name="id">Идентификатор Aonprd.</param>
|
||||
/// <returns>Суффикс для ссылки или пустая строка.</returns>
|
||||
public string GetSlugSuffix(string id)
|
||||
{
|
||||
return SlugSuffixes.TryGetValue(id, out string? slug) ? $"-{slug}" : string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Преобразовать JSON-объект в словарь.
|
||||
/// </summary>
|
||||
/// <param name="json">Исходный JSON-объект.</param>
|
||||
/// <param name="tokenPath">Путь к токену в JSON.</param>
|
||||
/// <returns>Результирующий словарь.</returns>
|
||||
public static Dictionary<string, string> JsonToDictionary(JObject json, string tokenPath)
|
||||
{
|
||||
return json.SelectToken(tokenPath)?.ToObject<Dictionary<string, string>>() ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Проверка уникальности:
|
||||
|
||||
SELECT
|
||||
E.type,
|
||||
E.slug,
|
||||
COUNT(*),
|
||||
string_agg(E.id::text, ', ' ORDER BY E.id),
|
||||
string_agg(EE.external_id::text, ', ' ORDER BY E.id)
|
||||
FROM public.entities AS E
|
||||
INNER JOIN public.entity_externals AS EE ON EE.entity_id = E.id
|
||||
GROUP BY E.type, E.slug
|
||||
HAVING COUNT(*) > 1 AND E.type NOT IN ('rule', 'action')
|
||||
*/
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
|
||||
internal static class AonprdProcessorInputExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Обработать строку, содержащую информацию о количестве действий.
|
||||
/// </summary>
|
||||
/// <param name="_"></param>
|
||||
/// <param name="input">Входная строка с данными.</param>
|
||||
/// <returns>Структура, хранящая информацию о количетсве действий.</returns>
|
||||
public static ActionStruct ResolveActionString(this ProcessorInput _, string input)
|
||||
{
|
||||
ActionStruct result = new();
|
||||
|
||||
switch (input)
|
||||
{
|
||||
case "Single Action":
|
||||
result.Actions = result.MaxActions = 1;
|
||||
break;
|
||||
|
||||
case "Two Actions":
|
||||
result.Actions = result.MaxActions = 2;
|
||||
break;
|
||||
|
||||
case "Three Actions":
|
||||
result.Actions = result.MaxActions = 3;
|
||||
break;
|
||||
|
||||
case "Reaction":
|
||||
result.IsReaction = true;
|
||||
break;
|
||||
|
||||
case "Free Action":
|
||||
result.IsFreeAction = false;
|
||||
break;
|
||||
|
||||
case "Single Action to Three Actions":
|
||||
case "Single Action or more Actions":
|
||||
result.Actions = 1;
|
||||
result.MaxActions = 3;
|
||||
break;
|
||||
|
||||
case "Single Action or Two Actions":
|
||||
case "Single Action to Two Actions":
|
||||
result.Actions = 1;
|
||||
result.MaxActions = 2;
|
||||
break;
|
||||
|
||||
case "Two Actions or Three Actions":
|
||||
result.Actions = 2;
|
||||
result.MaxActions = 3;
|
||||
break;
|
||||
|
||||
case "Two Actions to 2 rounds":
|
||||
result.Actions = 2;
|
||||
result.MaxActions = 3;
|
||||
result.TwoRounds = true;
|
||||
break;
|
||||
|
||||
case "Reaction or One Action":
|
||||
result.IsReaction = true;
|
||||
result.Actions = result.MaxActions = 1;
|
||||
break;
|
||||
|
||||
case "Reaction or Two Actions":
|
||||
result.IsReaction = true;
|
||||
result.Actions = result.MaxActions = 2;
|
||||
break;
|
||||
|
||||
case "Free Action or One Action":
|
||||
result.IsFreeAction = false;
|
||||
result.Actions = result.MaxActions = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
result.IsPassive = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Класс структуры, хранящей информацию о количетсве действий.
|
||||
/// </summary>
|
||||
public class ActionStruct
|
||||
{
|
||||
/// <summary>
|
||||
/// Количество действий
|
||||
/// </summary>
|
||||
public int Actions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Максимальное количество действий
|
||||
/// </summary>
|
||||
public int MaxActions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Флаг, указывающий, что действия не требуются.
|
||||
/// </summary>
|
||||
public bool IsPassive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Флаг, указывающий, что действие может быть использовано как реакция.
|
||||
/// </summary>
|
||||
public bool IsReaction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Флаг, указывающий, что можно использовать свободное действие.
|
||||
/// </summary>
|
||||
public bool IsFreeAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Флаг, указывающий, что действие может быть продлено до 2 раундов.
|
||||
/// </summary>
|
||||
public bool TwoRounds { get; set; }
|
||||
}
|
||||
|
||||
public class SourceCategorySolver : EnumSolver<SourceCategory>
|
||||
{
|
||||
public override Dictionary<string, SourceCategory> Data { get; } =
|
||||
new()
|
||||
{
|
||||
{ "Rulebooks", SourceCategory.Rulebooks },
|
||||
{ "Adventure Paths", SourceCategory.AdventurePaths },
|
||||
{ "Lost Omens", SourceCategory.LostOmens },
|
||||
{ "Adventures", SourceCategory.Adventures },
|
||||
{ "Comics", SourceCategory.Comics },
|
||||
{ "Blog Posts", SourceCategory.BlogPosts },
|
||||
{ "Society", SourceCategory.Society },
|
||||
};
|
||||
}
|
||||
|
||||
public class VisionEnumSolver : EnumSolver<VisionEnum>
|
||||
{
|
||||
public override Dictionary<string, VisionEnum> Data { get; } =
|
||||
new()
|
||||
{
|
||||
{ "Low-Light VisionEnum", VisionEnum.LowLightVision },
|
||||
{ "Darkvision", VisionEnum.DarkVision },
|
||||
};
|
||||
}
|
||||
|
||||
public class AttributeValuesSolver : EnumSolver<AttributeValues>
|
||||
{
|
||||
public override Dictionary<string, AttributeValues> Data { get; } =
|
||||
new()
|
||||
{
|
||||
{ "Consitution", AttributeValues.Constitution },
|
||||
{ "Other", AttributeValues.Free },
|
||||
{ "other", AttributeValues.Free },
|
||||
};
|
||||
}
|
||||
|
||||
public class ActionEnumSolver : EnumSolver<ActionEnum>
|
||||
{
|
||||
public override Dictionary<string, ActionEnum> Data { get; } =
|
||||
new()
|
||||
{
|
||||
{ "Single Action", ActionEnum.SingleAction },
|
||||
{ "Two Actions", ActionEnum.TwoActions },
|
||||
{ "Three Actions", ActionEnum.ThreeActions },
|
||||
{ "Reaction", ActionEnum.Reaction },
|
||||
{ "Free Action", ActionEnum.FreeAction },
|
||||
{ "Single Action to Three Actions", ActionEnum.SingleActionToThreeActions },
|
||||
{ "Single Action or more Actions", ActionEnum.SingleActionToThreeActions },
|
||||
{ "Single Action or Two Actions", ActionEnum.SingleActionToTwoActions },
|
||||
{ "Single Action to Two Actions", ActionEnum.SingleActionToTwoActions },
|
||||
{ "Two Actions or Three Actions", ActionEnum.TwoActionsToThreeActions },
|
||||
{ "Two Actions to 2 rounds", ActionEnum.TwoActionsToTwoRounds },
|
||||
{ "Reaction or One Action", ActionEnum.ReactionOrOneAction },
|
||||
{ "Reaction or Two Actions", ActionEnum.ReactionOrTwoAction },
|
||||
{ "Reaction or Three Actions", ActionEnum.ReactionOrThreeAction },
|
||||
{ "Free Action or One Action", ActionEnum.FreeActionOrOneAction },
|
||||
{ "1 Minute", ActionEnum.OneMinute },
|
||||
{ "1 minute", ActionEnum.OneMinute },
|
||||
{ "5 minutes", ActionEnum.FiveMinutes },
|
||||
{ "10 minutes", ActionEnum.TenMinutes },
|
||||
{ "30 minutes", ActionEnum.ThirtyMinutes },
|
||||
{ "1 hour", ActionEnum.OneHour },
|
||||
{ "<i>Nethys Note: No cast time was printed</i>", ActionEnum.Unknown },
|
||||
};
|
||||
}
|
||||
|
||||
public static void RegisterServices(IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddTransient<IEnumSolver, SourceCategorySolver>();
|
||||
serviceCollection.AddTransient<IEnumSolver, VisionEnumSolver>();
|
||||
serviceCollection.AddTransient<IEnumSolver, AttributeValuesSolver>();
|
||||
serviceCollection.AddTransient<IEnumSolver, ActionEnumSolver>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Pf2e.Database.Model.Base.Source;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Класс коллекции книг, содержащих правила.
|
||||
/// Реализует шаблон <c>Singleton</c>.
|
||||
/// </summary>
|
||||
internal class RuleTocCollection
|
||||
{
|
||||
/// <summary>
|
||||
/// Список книг, содержащих правила.
|
||||
/// </summary>
|
||||
public List<RuleTocBook> Books { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Поиск книги по числовому идентификатору.
|
||||
/// </summary>
|
||||
public RuleTocBook this[int id] =>
|
||||
Books.FirstOrDefault(i => i.SourceId == id) ?? throw new($"Book with id {id} not found");
|
||||
|
||||
/// <summary>
|
||||
/// Поиск книги по CLR-представлению источника.
|
||||
/// </summary>
|
||||
public RuleTocBook this[Source source]
|
||||
{
|
||||
get
|
||||
{
|
||||
RuleTocBook? result = Books.FirstOrDefault(i => i.SourceId == source.Id);
|
||||
|
||||
if (result is not null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = new(source);
|
||||
Books.Add(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Поиск книги по имени.
|
||||
/// </summary>
|
||||
public RuleTocBook? FindName(string name)
|
||||
{
|
||||
foreach (RuleTocBook book in Books)
|
||||
{
|
||||
if (book.IsNameExists(name))
|
||||
{
|
||||
return book;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Поиск правила по идентификатору.
|
||||
/// </summary>
|
||||
public RuleTocItem? FindEntityId(int id)
|
||||
{
|
||||
foreach (RuleTocBook book in Books)
|
||||
{
|
||||
RuleTocItem? result = book.GetByEntityId(id);
|
||||
|
||||
if (result is not null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает строковое представление коллекции в файле YAML.
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Join("\n", Books.Select(book => book.ToString()).ToList());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Сохраняет коллекцию в файле YAML.
|
||||
/// </summary>
|
||||
public void SaveFile()
|
||||
{
|
||||
string fileName =
|
||||
$"rules-toc.{new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds()}.debug.yaml";
|
||||
|
||||
using FileStream fileStream = File.Create(fileName);
|
||||
using StreamWriter writer = new(fileStream);
|
||||
|
||||
writer.Write(ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Экземпляр класса <see cref="RuleTocCollection"/>.
|
||||
/// </summary>
|
||||
public static RuleTocCollection Instance { get; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Класс представляет собой книгу, содержащую правила.
|
||||
/// </summary>
|
||||
internal class RuleTocBook(Source source)
|
||||
{
|
||||
/// <summary>
|
||||
/// Идентификатор источника.
|
||||
/// </summary>
|
||||
public int SourceId { get; } = source.Id;
|
||||
|
||||
/// <summary>
|
||||
/// Названия источника.
|
||||
/// </summary>
|
||||
public string SourceName { get; } = source.Name;
|
||||
|
||||
/// <summary>
|
||||
/// Список дочерних правил.
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// Список дочерних элементов.
|
||||
/// </summary>
|
||||
public List<RuleTocItem> Children { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Находит элемент по хлебным крошкам.
|
||||
/// </summary>
|
||||
/// <param name="breadcrumbs">Массив хлебных крошек, указывающих на путь в дереве.</param>
|
||||
/// <returns><see cref="RuleTocItem"/> или <c>null</c> если элемент не найден.</returns>
|
||||
public RuleTocItem Get(string[] breadcrumbs)
|
||||
{
|
||||
RuleTocItem? node = null;
|
||||
|
||||
while (true)
|
||||
{
|
||||
List<RuleTocItem> children = node?.Children ?? Children;
|
||||
|
||||
if (breadcrumbs.Length == 0)
|
||||
{
|
||||
return node!;
|
||||
}
|
||||
|
||||
string root = breadcrumbs[0];
|
||||
RuleTocItem? item = children.FirstOrDefault(i => i.Name == root);
|
||||
|
||||
if (item is null)
|
||||
{
|
||||
item = new(root, node);
|
||||
children.Add(item);
|
||||
}
|
||||
|
||||
breadcrumbs = breadcrumbs[1..];
|
||||
node = item;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверяет, существует ли имя в текущей книге или дочерних элементах.
|
||||
/// </summary>
|
||||
/// <param name="name">Имя для проверки.</param>
|
||||
/// <param name="node">Начальный элемент для поиска.</param>
|
||||
/// <returns>true если имя.</returns>
|
||||
public bool IsNameExists(string name, RuleTocItem? node = null)
|
||||
{
|
||||
foreach (RuleTocItem item in node?.Children ?? Children)
|
||||
{
|
||||
if (item.Name == name || IsNameExists(name, item))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Находит элемент по идентификатору сущности.
|
||||
/// </summary>
|
||||
/// <param name="id">Идентификатор сущности.</param>
|
||||
/// <param name="node">Начальный узел для поиска.</param>
|
||||
/// <returns><see cref="RuleTocItem"/> или <c>null</c> если элемент не найден.</returns>
|
||||
public RuleTocItem? GetByEntityId(int id, RuleTocItem? node = null)
|
||||
{
|
||||
if (node?.RuleId == id)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
foreach (RuleTocItem item in node?.Children ?? Children)
|
||||
{
|
||||
RuleTocItem? result = GetByEntityId(id, item);
|
||||
|
||||
if (result is not null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает строковое представление книги в файле YAML.
|
||||
/// </summary>
|
||||
/// <returns>Строковое представление книги.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"\"{SourceName}\":\n"
|
||||
+ string.Join(
|
||||
"\n",
|
||||
Children.Select(child => RuleTocItem.Indent(child.ToString())).ToList()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Класс представляет собой элемент дерева правил.
|
||||
/// </summary>
|
||||
internal class RuleTocItem(string name, RuleTocItem? parent)
|
||||
{
|
||||
public string? Id { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Имя элемента.
|
||||
/// </summary>
|
||||
public string Name { get; } = name;
|
||||
|
||||
/// <summary>
|
||||
/// Идентификатор правила.
|
||||
/// </summary>
|
||||
public int? RuleId { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Указывает, что элемент обрабатывается.
|
||||
/// </summary>
|
||||
public bool IsHandled { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Родительский элемент дерева.
|
||||
/// </summary>
|
||||
public RuleTocItem? Parent { get; } = parent;
|
||||
|
||||
/// <summary>
|
||||
/// Порядок дочерних элементов.
|
||||
/// </summary>
|
||||
public List<string>? ChildrenOrder { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Коллекция дочерних элементов.
|
||||
/// </summary>
|
||||
public List<RuleTocItem> Children { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Предыдущий идентификатор.
|
||||
/// </summary>
|
||||
public string? PreviousId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Следующий идентификатор.
|
||||
/// </summary>
|
||||
public string? NextId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Идентификатор первого дочернего элемента.
|
||||
/// </summary>
|
||||
public string? FirstChildId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Идентификатор последнего дочернего элемента.
|
||||
/// </summary>
|
||||
public string? LastChildId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Возвращает строковое представление элемента содержания в файле YAML.
|
||||
/// </summary>
|
||||
/// <returns>Строковое представление элемента содержания.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
List<string> rows =
|
||||
[
|
||||
$"{Name}:",
|
||||
$"{Tab}aonprd: {Id ?? "null"}",
|
||||
$"{Tab}entity: {RuleId?.ToString() ?? "null"}",
|
||||
];
|
||||
|
||||
if (Children.Count == 0)
|
||||
{
|
||||
// rows.Add($"{TAB}children: None");
|
||||
return string.Join("\n", rows);
|
||||
}
|
||||
|
||||
rows.Add($"{Tab}children:");
|
||||
|
||||
foreach (RuleTocItem child in Children)
|
||||
{
|
||||
rows.Add(child.Indent(2));
|
||||
}
|
||||
|
||||
return string.Join("\n", rows);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Увеличение отступа строкового представления элемента содержания в файле YAML.
|
||||
/// </summary>
|
||||
/// <param name="amount">Количество отступов.</param>
|
||||
/// <returns>Строковое представление элемента содержания с отступом.</returns>
|
||||
/// <seealso cref="Tab"/>
|
||||
public string Indent(int amount = 1)
|
||||
{
|
||||
string result = ToString();
|
||||
for (int i = 0; i < amount; i++)
|
||||
{
|
||||
result = Indent(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Увеличение отступа строки.
|
||||
/// </summary>
|
||||
/// <param name="str">Входная строка.</param>
|
||||
/// <returns>Строка с отступом.</returns>
|
||||
/// <seealso cref="Tab"/>
|
||||
public static string Indent(string str)
|
||||
{
|
||||
return Tab + str.Replace("\n", $"\n{Tab}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Строка отступа строки.
|
||||
/// </summary>
|
||||
/// <seealso cref="Indent(int)"/>
|
||||
/// <seealso cref="Indent(string)"/>
|
||||
public const string Tab = " ";
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Класс-помощник, для обработки строкового ввода с Архивов Нефиса.
|
||||
/// Реализует шаблон <c>Singleton</c>.
|
||||
/// </summary>
|
||||
internal partial class StringHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Конструктор класса <see cref="StringHelper"/>
|
||||
/// </summary>
|
||||
public StringHelper() { }
|
||||
|
||||
/// <summary>
|
||||
/// Разбиение строки по нестабильным строковым разделителям (например, <c>", "</c>, <c>" or "</c> и т.д.).
|
||||
/// </summary>
|
||||
/// <param name="value">Исходная строка.</param>
|
||||
/// <returns>Коллекция строк.</returns>
|
||||
public List<string> RowSplit(string value)
|
||||
{
|
||||
return value
|
||||
.Replace(", or", ",")
|
||||
.Replace(" or ", ", ")
|
||||
.Replace(";", ",")
|
||||
.Split(", ")
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Разбор списка ссылок в исходной строке.
|
||||
/// </summary>
|
||||
/// <param name="input">Исходная строка.</param>
|
||||
/// <returns>Структура, содеражащая информацию разбиении строки по ссылкам.</returns>
|
||||
public MarkdownLinkSplit ParseMarkdownLinks(string input)
|
||||
{
|
||||
MarkdownLinkSplit result = new();
|
||||
|
||||
MatchCollection matches = LinkRegex().Matches(input);
|
||||
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
result.Links.Add(
|
||||
new()
|
||||
{
|
||||
Prefix = match.Groups[1].Value.Trim(),
|
||||
Text = match.Groups[2].Value.Trim(),
|
||||
Url = match.Groups[3].Value.Trim(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
result.Suffix = LinkRegex().Replace(input, "");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Извлечение суффикса из описания источника.
|
||||
/// </summary>
|
||||
/// <param name="input">Исходная строка.</param>
|
||||
/// <returns>Суффикс.</returns>
|
||||
public string ResolveSourceSuffix(string input)
|
||||
{
|
||||
Match match = SourceSuffixRegex().Match(input);
|
||||
return match.Captures.Count > 0 ? match.Groups[1].Value : "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Регулярное выражение для извлечения источника из строки с Markdown-ссылкой.
|
||||
/// </summary>
|
||||
/// <returns>Регулярное выражение.</returns>
|
||||
[GeneratedRegex(@"^\[.*?\]\(.*?\)\s+(.*)$")]
|
||||
public static partial Regex SourceSuffixRegex();
|
||||
|
||||
/// <summary>
|
||||
/// Регулярное выражение для выявления Markdown-ссылок в строке.
|
||||
/// </summary>
|
||||
/// <returns>Регулярное выражение.</returns>
|
||||
[GeneratedRegex(@"(.*?)\[(.*?)\]\((.*?)\)")]
|
||||
public static partial Regex LinkRegex();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Класс структуры, содеражащая информацию разбиении строки по ссылкам.
|
||||
/// </summary>
|
||||
internal class MarkdownLinkSplit
|
||||
{
|
||||
/// <summary>
|
||||
/// Список содержащихся ссылок.
|
||||
/// </summary>
|
||||
public List<MarkdownLink> Links { get; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Завершающая часть ссылки.
|
||||
/// </summary>
|
||||
public string Suffix { get; set; } = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Информация о ссылке в строке.
|
||||
/// </summary>
|
||||
internal class MarkdownLink
|
||||
{
|
||||
/// <summary>
|
||||
/// Данные, содержащиеся до ссылки.
|
||||
/// </summary>
|
||||
public string Prefix { get; init; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Текст ссылки.
|
||||
/// </summary>
|
||||
public string Text { get; init; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// URL ссылки.
|
||||
/// </summary>
|
||||
public string Url { get; init; } = "";
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Definitions;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model;
|
||||
using Pf2e.Database.Model.Base;
|
||||
using Pf2e.Database.Model.Base.Source;
|
||||
using Pf2e.Database.Model.Base.Targets;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors;
|
||||
|
||||
/// <summary>
|
||||
/// Абстрактный класс-обработчик сущностей, полученных из Архивов Нефиса.
|
||||
/// Класс предназначен для обработки данных с помощью различных обработчиков,
|
||||
/// для которых указан атрибут <see cref="ProcessorAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="input">Объект обработки вводимого JSON.</param>
|
||||
/// <param name="stringHelper">[DI] Помощник обработки строк.</param>
|
||||
/// <param name="helper">[DI] Помощник работы с БД.</param>
|
||||
/// <param name="globals">[DI] Глобальные параметра обработки Архивов Нефиса.</param>
|
||||
/// <seealso cref="ProcessorAttribute"/>
|
||||
internal abstract class AbstractEntityProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractInputProcessor(input)
|
||||
{
|
||||
/// <inheritdoc cref="Pf2eDbContext"/>
|
||||
public Pf2eDbContext Context { get; } = new();
|
||||
|
||||
/// <inheritdoc cref="StringHelper"/>
|
||||
public Helpers_StringHelper StringHelper { get; } = stringHelper;
|
||||
|
||||
/// <inheritdoc cref="DatabaseHelper"/>
|
||||
public DatabaseHelper Helper { get; } = helper;
|
||||
|
||||
/// <inheritdoc cref="AonprdBuilderGlobals"/>
|
||||
public AonprdBuilderGlobals Globals { get; } = globals;
|
||||
|
||||
/// <summary>
|
||||
/// Корневая сущность.
|
||||
/// </summary>
|
||||
public Entity Entity { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Тип сущности.
|
||||
/// </summary>
|
||||
public abstract EntityType Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Основная сущность.
|
||||
/// </summary>
|
||||
public abstract IEntity Object { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Название сущности, которое будет использоваться для обработки данных.
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return _name ??= GetEntityName(); }
|
||||
}
|
||||
private string? _name = null;
|
||||
|
||||
/// <summary>
|
||||
/// Добавление основной сущности в контекст базы данных.
|
||||
/// </summary>
|
||||
protected abstract void Add();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
Check();
|
||||
|
||||
AddEntity();
|
||||
AddSource();
|
||||
AddExternal();
|
||||
AddTraits();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Save()
|
||||
{
|
||||
Add();
|
||||
Context.SaveChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверки необходимости импорта сущности.
|
||||
/// </summary>
|
||||
public virtual void Check()
|
||||
{
|
||||
string id = Input.GetRequired<string>("id");
|
||||
|
||||
if (Globals.Ignore.Contains(id))
|
||||
{
|
||||
throw new SkipItemException(Name, "игнорируется.");
|
||||
}
|
||||
|
||||
if (Globals.MergeSources.ContainsKey(id))
|
||||
{
|
||||
throw new SkipItemException(Name, "помечено на слияние.");
|
||||
}
|
||||
}
|
||||
|
||||
#region "Генерация описания"
|
||||
|
||||
/// <summary>
|
||||
/// Получение списка полей, которые должны быть добавлены в описание.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
// [Obsolete("Данный метод будет отключён на финальных этапах разработки.")]
|
||||
protected virtual ICollection<string> AddedDescriptionPaths() => [];
|
||||
|
||||
/// <summary>
|
||||
/// Создание строкового представления объекта по указанному пути для добавления к описанию сущности.
|
||||
/// </summary>
|
||||
/// <param name="path">Путь к добавляемому объекту.</param>
|
||||
/// <returns>Строковое представление для добавления к описанию сущности.</returns>
|
||||
// [Obsolete("Данный метод будет отключён на финальных этапах разработки.")]
|
||||
protected string AddedDescription(string path) =>
|
||||
$"\r\n\r\n========== [{path}] ==========\r\n\r\n{Input.GetOptional<object?>(path)?.ToString() ?? ""}";
|
||||
|
||||
/// <summary>
|
||||
/// Создание строкового представления объектов по указанным путям для добавления к описанию сущности.
|
||||
/// </summary>
|
||||
/// <param name="paths">Список путей к добавляемым объектам.</param>
|
||||
/// <returns>Строковое представление для добавления к описанию сущности.</returns>
|
||||
// [Obsolete("Данный метод будет отключён на финальных этапах разработки.")]
|
||||
protected string AddedDescription(ICollection<string> paths) =>
|
||||
string.Join("", paths.Select(AddedDescription));
|
||||
|
||||
/// <summary>
|
||||
/// Сгенерировать описание сущности.
|
||||
/// </summary>
|
||||
/// <returns>Описание сущности</returns>
|
||||
protected virtual string GetDescription() =>
|
||||
Input.GetRequired<string>("markdown") + AddedDescription(AddedDescriptionPaths());
|
||||
|
||||
/// <summary>
|
||||
/// Генерация JSON-строки из объектов, располагаюхися по путям, указанным в <paramref name="paths"/>.
|
||||
/// </summary>
|
||||
/// <param name="paths">Коллекция путей, из которых необходимо достатить объекты.</param>
|
||||
/// <returns>JSON-строка.</returns>
|
||||
protected string GenerateJsonString(params ICollection<string> paths)
|
||||
{
|
||||
Dictionary<string, object?> data = [];
|
||||
|
||||
foreach (string key in paths)
|
||||
{
|
||||
data.Add(key, Input.Input.SelectToken(key));
|
||||
}
|
||||
|
||||
return JsonConvert.SerializeObject(data, new JsonSerializerSettings());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region "Генерация сущности"
|
||||
|
||||
/// <summary>
|
||||
/// Получает имя сущности из входных данных.
|
||||
/// </summary>
|
||||
/// <returns>Имя сущности.</returns>
|
||||
protected virtual string GetEntityName() => Input.GetRequired<string>("name").Replace("’", "'");
|
||||
|
||||
/// <summary>
|
||||
/// Генерация основных полей корневой сущности.
|
||||
/// </summary>
|
||||
protected virtual void AddEntity()
|
||||
{
|
||||
lock (Helper.IdLock)
|
||||
{
|
||||
Entity.Id = Helper.NextEntityId;
|
||||
}
|
||||
|
||||
Entity.Type = Type;
|
||||
Entity.Name[LocaleType.English] = Name;
|
||||
Entity.Img = "";
|
||||
Entity.Description = GetDescription();
|
||||
Entity.Rarity = Input.EnumOptional("rarity", EntityRarity.Common);
|
||||
Entity.Slug =
|
||||
Helper.GenerateSlug(Entity.Name[LocaleType.English])
|
||||
+ Globals.GetSlugSuffix(Input.GetRequired<string>("id"));
|
||||
Entity.IsTranslated = false;
|
||||
Entity.IsChecked = false;
|
||||
|
||||
Object.Entity = Entity;
|
||||
Object.Id = Entity.Id;
|
||||
|
||||
Context.Entities.Add(Entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Генерация источников сущности.
|
||||
/// </summary>
|
||||
protected virtual void AddSource()
|
||||
{
|
||||
string[] sourceNames = Input
|
||||
.GetRequired<JArray>("source")
|
||||
.Select(token => token.ToString())
|
||||
.ToArray();
|
||||
|
||||
if (sourceNames.Length == 0)
|
||||
{
|
||||
throw new(
|
||||
$"Источники для сущности \"{Entity.Name[LocaleType.English]}\" "
|
||||
+ $"(Aonprd id \"{Input.GetRequired<string>("id")}\") не найдены."
|
||||
);
|
||||
}
|
||||
|
||||
foreach (string sourceName in sourceNames)
|
||||
{
|
||||
EntitySource entitySource = new()
|
||||
{
|
||||
Entity = Entity,
|
||||
SourceId = Globals.SourceIds[sourceName.Trim()],
|
||||
Suffix = StringHelper.ResolveSourceSuffix(
|
||||
Input.GetRequired<string>("source_markdown")
|
||||
),
|
||||
IsRemaster = Input.GetOptional<JArray>("legacy_id") is not null,
|
||||
};
|
||||
|
||||
Entity.Sources.Add(entitySource);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Генерация внешних ссылок сущности.
|
||||
/// </summary>
|
||||
protected virtual void AddExternal()
|
||||
{
|
||||
EntityExternal external = new()
|
||||
{
|
||||
Entity = Entity,
|
||||
TargetId = Globals.AonprdTarget.Id,
|
||||
ExternalId = Input.GetRequired<string>("id"),
|
||||
Suffix = Input.GetRequired<string>("url"),
|
||||
Md5 = Input.Md5(),
|
||||
};
|
||||
|
||||
Entity.Externals.Add(external);
|
||||
Context.EntityExternals.Add(external);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Генерация списка признаков сущности.
|
||||
/// </summary>
|
||||
protected virtual void AddTraits()
|
||||
{
|
||||
JToken? traitsJson = Input.Input.SelectToken("trait");
|
||||
|
||||
if (traitsJson?.Type != JTokenType.Array)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> names = traitsJson.ToArray().Select(jToken => jToken.ToString()).ToList();
|
||||
|
||||
List<int> traitIds = names.Select(name => Globals.TraitIds[name]).ToList();
|
||||
|
||||
List<Trait> traits = Context.Traits.Where(t => traitIds.Contains(t.Id)).ToList();
|
||||
|
||||
foreach (Trait trait in traits)
|
||||
{
|
||||
Entity.Traits.Add(trait);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Base;
|
||||
using Pf2e.Database.Model.Common;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors;
|
||||
|
||||
/// <summary>
|
||||
/// Абстрактный класс-обработчик сущностей подклассов, полученных из Архивов Нефиса.
|
||||
/// Класс предназначен для обработки данных с помощью различных обработчиков,
|
||||
/// для которых указан атрибут <see cref="ProcessorAttribute"/>.
|
||||
/// </summary>
|
||||
internal abstract class AbstractSubclassProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Subclass;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract override Subclass Object { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Название подкласса.
|
||||
/// </summary>
|
||||
public abstract string? ClassName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Название группы подклассов.
|
||||
/// </summary>
|
||||
public abstract string GroupName { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Subclasses.Add(Object);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
|
||||
Object.Group = GetGroup();
|
||||
ProcessObject();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка полей подкласса.
|
||||
/// </summary>
|
||||
public abstract void ProcessObject();
|
||||
|
||||
/// <summary>
|
||||
/// Получение CLR-представления группы подклассов, к которому относится обрабатываемый подкласс.
|
||||
/// </summary>
|
||||
/// <returns>CLR-представления группы подклассов.</returns>
|
||||
public SubclassGroup GetGroup()
|
||||
{
|
||||
return Context.SubclassGroups.First(g =>
|
||||
Pf2eDbContext.LocaleSearch(g.Entity.Name, GroupName)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавление заклинаний из строкового представления.
|
||||
/// </summary>
|
||||
/// <param name="spellMd">Строковое представление списка заклинаний.</param>
|
||||
public void AddSpells(string spellMd)
|
||||
{
|
||||
List<string> spellUrls = StringHelper
|
||||
.ParseMarkdownLinks(spellMd)
|
||||
.Links.Select(l => l.Url)
|
||||
.ToList();
|
||||
|
||||
List<int> spellIds = Context
|
||||
.EntityExternals.Where(x => spellUrls.Contains(x.Suffix))
|
||||
.Select(x => x.Entity.Id)
|
||||
.ToList();
|
||||
|
||||
List<Entity> spells = Context
|
||||
.Spells.Where(s => spellIds.Contains(s.Id))
|
||||
.Select(s => s.Entity)
|
||||
.ToList();
|
||||
|
||||
foreach (Entity spellEntity in spells)
|
||||
{
|
||||
Object.Entities.Add(spellEntity);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавление тренировок из строкового представления.
|
||||
/// </summary>
|
||||
/// <param name="trainingMd">Строковое представление списка тренировок.</param>
|
||||
public void AddTrainings(string trainingMd)
|
||||
{
|
||||
List<string> trainingNames = trainingMd.Split(", ").ToList();
|
||||
List<Training> trainings = Context
|
||||
.Trainings.Where(t => Pf2eDbContext.LocaleSearchArray(t.Name, trainingNames))
|
||||
.ToList();
|
||||
|
||||
foreach (string name in trainingNames)
|
||||
{
|
||||
Training? training = trainings.FirstOrDefault(t => t.Name.Contains(name));
|
||||
training ??= new()
|
||||
{
|
||||
Name = new() { { LocaleType.English, name } },
|
||||
Type = TrainingType.Lore,
|
||||
};
|
||||
|
||||
Object.Trainings.Add(
|
||||
new()
|
||||
{
|
||||
Subclass = Object,
|
||||
Training = training,
|
||||
Rank = TrainingRank.Trained,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Definitions;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Base;
|
||||
using Pf2e.Database.Model.Base.Targets;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Finalization;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:legacy-remaster",
|
||||
InnerType = null,
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Связь устаревших и обновлённых сущностей",
|
||||
Group = ProcessorGroupEnum.AonprdFinalization,
|
||||
Parallel = true
|
||||
)]
|
||||
internal class LegacyRemasterProcessors(ProcessorInput input) : AbstractInputProcessor(input)
|
||||
{
|
||||
private Pf2eDbContext Context { get; } = new();
|
||||
|
||||
public override void Process()
|
||||
{
|
||||
string aonprdId = Input.GetRequired<string>("id");
|
||||
EntityExternal entity =
|
||||
Context.EntityExternals.AsNoTracking().FirstOrDefault(x => x.ExternalId == aonprdId)
|
||||
?? throw new SilentSkipItemException();
|
||||
int entityId = entity.EntityId;
|
||||
Entity legacyEntity =
|
||||
Context.Entities.FirstOrDefault(e => e.Id == entityId)
|
||||
?? throw new($"Неизвестная сущность с ID {entityId}");
|
||||
|
||||
legacyEntity.IsLegacy = true;
|
||||
|
||||
foreach (int remasterId in GetEntityIds("remaster_id"))
|
||||
{
|
||||
Context.LegacyRemasters.Add(new() { LegacyId = entityId, RemasterId = remasterId });
|
||||
Entity remasterEntity =
|
||||
Context.Entities.AsNoTracking().FirstOrDefault(e => e.Id == remasterId)
|
||||
?? throw new($"Неизвестная сущность с ID {remasterId}");
|
||||
|
||||
if (legacyEntity.Slug == remasterEntity.Slug)
|
||||
{
|
||||
legacyEntity.Slug += "-legacy";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected List<int> GetEntityIds(string path)
|
||||
{
|
||||
List<string> aonprdIds = (Input.GetOptional<JArray>(path) ?? [])
|
||||
.Select(token => token.ToString())
|
||||
.ToList();
|
||||
|
||||
return Context
|
||||
.EntityExternals.AsNoTracking()
|
||||
.Where(x => aonprdIds.Contains(x.ExternalId!))
|
||||
.Select(x => x.EntityId)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public override void Save()
|
||||
{
|
||||
Context.SaveChanges();
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Definitions;
|
||||
using Pf2e.Scrapper.Processors.Factory;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Base;
|
||||
using Pf2e.Database.Model.Base.Targets;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Finalization;
|
||||
|
||||
[ProcessorFactory(
|
||||
"aonprd:fix-legacy-remaster",
|
||||
ProcessorType = typeof(MissingLegacyRemasterProcessor),
|
||||
Description = "Дополнение связяй устаревших и обновлённых сущностей",
|
||||
Group = ProcessorGroupEnum.AonprdFinalization,
|
||||
Parallel = true
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:legacy-remaster"])]
|
||||
internal class MissingLegacyRemasterProcessorFactory(
|
||||
IServiceProvider serviceProvider,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractProcessorFactory
|
||||
{
|
||||
public IServiceProvider ServiceProvider { get; } = serviceProvider;
|
||||
public AonprdBuilderGlobals Globals { get; } = globals;
|
||||
|
||||
public override int Count() => Globals.LegacyRemasterExtra.Count;
|
||||
|
||||
public override IEnumerable<Tuple<string, IProcessor>> GetEnumerator()
|
||||
{
|
||||
foreach ((string key, string value) in Globals.LegacyRemasterExtra)
|
||||
{
|
||||
yield return new(
|
||||
$"{key} -> {value}",
|
||||
ActivatorUtilities.CreateInstance<MissingLegacyRemasterProcessor>(
|
||||
ServiceProvider,
|
||||
key,
|
||||
value
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class MissingLegacyRemasterProcessor(string legacyId, string remasterId) : IProcessor
|
||||
{
|
||||
public Pf2eDbContext Context { get; } = new();
|
||||
public string LegacyId { get; } = legacyId;
|
||||
public string RemasterId { get; } = remasterId;
|
||||
|
||||
private Entity GetEntity(string aonprdId)
|
||||
{
|
||||
EntityExternal entity =
|
||||
Context.EntityExternals.AsNoTracking().FirstOrDefault(x => x.ExternalId == aonprdId)
|
||||
?? throw new SilentSkipItemException();
|
||||
|
||||
int entityId = entity.EntityId;
|
||||
|
||||
return Context.Entities.FirstOrDefault(e => e.Id == entityId)
|
||||
?? throw new($"Неизвестная сущность с ID {entityId}");
|
||||
}
|
||||
|
||||
public void Process()
|
||||
{
|
||||
Entity legacyEntity = GetEntity(LegacyId);
|
||||
Entity remasterEntity = GetEntity(RemasterId);
|
||||
|
||||
TestExist(legacyEntity, remasterEntity);
|
||||
|
||||
Context.LegacyRemasters.Add(
|
||||
new() { LegacyId = legacyEntity.Id, RemasterId = remasterEntity.Id }
|
||||
);
|
||||
|
||||
legacyEntity.IsLegacy = true;
|
||||
|
||||
if (legacyEntity.Slug == remasterEntity.Slug)
|
||||
{
|
||||
legacyEntity.Slug += "-legacy";
|
||||
}
|
||||
}
|
||||
|
||||
public void TestExist(Entity legacyEntity, Entity remasterEntity)
|
||||
{
|
||||
if (
|
||||
Context
|
||||
.LegacyRemasters.AsNoTracking()
|
||||
.Any(x => x.LegacyId == legacyEntity.Id && x.RemasterId == remasterEntity.Id)
|
||||
)
|
||||
{
|
||||
throw new SilentSkipItemException();
|
||||
}
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
Context.SaveChanges();
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Compendium;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Definitions;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Preparation;
|
||||
|
||||
[Processor(
|
||||
"aonprd:compendium",
|
||||
Description = "Загрузка компендиума",
|
||||
Group = ProcessorGroupEnum.AonprdPreparation
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:repository"])]
|
||||
internal class CompendiumLoadProcessor(
|
||||
AonprdRepository repository,
|
||||
AonprdCompendium compendium,
|
||||
ProcessProgress progress
|
||||
) : IProcessor
|
||||
{
|
||||
public AonprdRepository Repository { get; } = repository;
|
||||
public AonprdCompendium Compendium { get; } = compendium;
|
||||
public ProcessProgress Progress { get; } = progress;
|
||||
|
||||
public void Process()
|
||||
{
|
||||
using StreamReader indexFile = new(
|
||||
Path.Combine(Repository.RepositoryDirPath, "index.json")
|
||||
);
|
||||
JObject indexJson = JObject.Parse(indexFile.ReadToEnd());
|
||||
|
||||
Progress.Local.Reset(indexJson.Count);
|
||||
|
||||
foreach ((string file, JToken? value) in indexJson)
|
||||
{
|
||||
Progress.Local.Start(file);
|
||||
|
||||
JArray items = (JArray)value!;
|
||||
|
||||
foreach (JToken item in items)
|
||||
{
|
||||
AonprdCompendiumItem compendiumItem = new(item.ToString(), file);
|
||||
|
||||
Compendium.Items.Add(compendiumItem);
|
||||
}
|
||||
|
||||
Progress.Local.End();
|
||||
}
|
||||
|
||||
Progress.Local.Complete();
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
List<AonprdCompendiumItem> result = Compendium.Items.OrderBy(item => item.Id).ToList();
|
||||
|
||||
Compendium.Items.Clear();
|
||||
foreach (AonprdCompendiumItem item in result)
|
||||
{
|
||||
Compendium.Items.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Definitions;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Base.Targets;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Preparation;
|
||||
|
||||
[Processor(
|
||||
"aonprd:external",
|
||||
Description = "Создание цели внешних ссылок",
|
||||
Group = ProcessorGroupEnum.AonprdPreparation
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:repository"])]
|
||||
internal class ExternalProcessor(AonprdBuilderGlobals globals) : AbstractSimpleProcessor
|
||||
{
|
||||
public Pf2eDbContext Context { get; } = new();
|
||||
public AonprdBuilderGlobals Globals { get; } = globals;
|
||||
|
||||
public ExternalTarget AonprdTarget = null!;
|
||||
|
||||
public override void Process()
|
||||
{
|
||||
AonprdTarget = new()
|
||||
{
|
||||
Name = AonprdImporter.TargetName,
|
||||
Icon = "http://www.google.com/s2/favicons?domain=2e.aonprd.com",
|
||||
Prefix = "https://2e.aonprd.com",
|
||||
};
|
||||
}
|
||||
|
||||
public override void Save()
|
||||
{
|
||||
Context.ExternalTargets.Add(AonprdTarget);
|
||||
Context.SaveChanges();
|
||||
|
||||
Globals.AonprdTarget = AonprdTarget;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Definitions;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Preparation;
|
||||
|
||||
[Processor(
|
||||
"aonprd:repository",
|
||||
Description = "Обновление репозитория",
|
||||
Group = ProcessorGroupEnum.AonprdPreparation
|
||||
)]
|
||||
internal class RepositoryUpdateProcessor(AonprdRepository repository, ProcessProgress progress)
|
||||
: IProcessor
|
||||
{
|
||||
public AonprdRepository Repository { get; } = repository;
|
||||
public ProcessProgress Progress { get; } = progress;
|
||||
|
||||
public void Process()
|
||||
{
|
||||
Repository.Update(Progress);
|
||||
}
|
||||
|
||||
public void Save() { }
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Compendium;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.SchemaBuilder;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Preparation;
|
||||
|
||||
[Processor(
|
||||
"aonprd:schema",
|
||||
Description = "Построение схемы данных",
|
||||
Group = ProcessorGroupEnum.AonprdPreparation,
|
||||
Active = false
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:repository", "aonprd:compendium"])]
|
||||
internal class SchemaBuildProcessor(
|
||||
AonprdImporter importer,
|
||||
AonprdCompendium compendium,
|
||||
ProcessProgress progress,
|
||||
ApplicationSettings settings
|
||||
) : AbstractSchemaBuildProcessor
|
||||
{
|
||||
/// <inheritdoc cref="AonprdImporter"/>
|
||||
protected AonprdImporter Importer { get; } = importer;
|
||||
|
||||
/// <inheritdoc cref="AonprdCompendium"/>
|
||||
protected override AonprdCompendium Compendium { get; } = compendium;
|
||||
|
||||
/// <inheritdoc cref="ProcessProgress"/>
|
||||
protected override ProcessProgress Progress { get; } = progress;
|
||||
|
||||
/// <inheritdoc cref="ApplicationSettings"/>
|
||||
protected ApplicationSettings Settings { get; } = settings;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string SavePath => Path.Combine(Settings.OutputDirPath, Importer.Slug);
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override AonprdTypeResolver Resolver { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Список типов, являющихся подклассами.
|
||||
/// </summary>
|
||||
private readonly string[] _subclassSchemaTypes =
|
||||
[
|
||||
"research-field",
|
||||
"apparition",
|
||||
"practice",
|
||||
"instinct",
|
||||
"muse",
|
||||
"cause",
|
||||
"tenet",
|
||||
"doctrine",
|
||||
"druidic-order",
|
||||
"methodology",
|
||||
"element",
|
||||
"hybrid-study",
|
||||
"mystery",
|
||||
"conscious-mind",
|
||||
"subconscious-mind",
|
||||
"hunters-edge",
|
||||
"racket",
|
||||
"bloodline",
|
||||
"style",
|
||||
"implement",
|
||||
"lesson",
|
||||
"patron",
|
||||
"arcane-school",
|
||||
"arcane-thesis",
|
||||
"way",
|
||||
"innovation",
|
||||
"ikon",
|
||||
"epithet",
|
||||
];
|
||||
|
||||
protected override ICollection<string> GetSchemaNodes(AbstractCompendiumItem item)
|
||||
{
|
||||
List<string> nodes = [item.Type];
|
||||
|
||||
// Нода подкласса
|
||||
if (_subclassSchemaTypes.Contains(item.Type))
|
||||
{
|
||||
nodes.Add("_subclass");
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
internal class AonprdTypeResolver : TypeResolver
|
||||
{
|
||||
//
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Definitions;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Common;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Preparation;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:skill",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
InnerType = "skill",
|
||||
Description = "Навыки",
|
||||
Group = ProcessorGroupEnum.AonprdPreparation
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:compendium"])]
|
||||
internal class SkillProcessor(ProcessorInput input, Pf2eDbContext context)
|
||||
: AbstractInputProcessor(input)
|
||||
{
|
||||
public Pf2eDbContext Context { get; } = context;
|
||||
|
||||
/// <summary>
|
||||
/// Обучаемый объект.
|
||||
/// </summary>
|
||||
public Training Training = null!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Save() => Context.Trainings.Add(Training);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
Training = new()
|
||||
{
|
||||
Name = new() { { LocaleType.English, Input.GetRequired<string>("name") } },
|
||||
Type = TrainingType.Skill,
|
||||
};
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Definitions;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Base.Source;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Preparation;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:source",
|
||||
InnerType = "source",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Источники",
|
||||
Group = ProcessorGroupEnum.AonprdPreparation
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:compendium"])]
|
||||
internal class SourceProcessor(ProcessorInput input, AonprdBuilderGlobals globals)
|
||||
: AbstractInputProcessor(input)
|
||||
{
|
||||
public AonprdBuilderGlobals Globals { get; } = globals;
|
||||
public Pf2eDbContext Context { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Источник сущности.
|
||||
/// </summary>
|
||||
protected Source Source = null!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
Source = new()
|
||||
{
|
||||
Name = Input.GetRequired<string>("name"),
|
||||
Category = Input.EnumRequired<SourceCategory>("primary_source_category"),
|
||||
ReleaseDate = DateOnly.Parse(Input.GetRequired<string>("release_date")),
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Save()
|
||||
{
|
||||
Context.Sources.Add(Source);
|
||||
Context.SaveChanges();
|
||||
|
||||
Globals.SourceIds.Add(Source.Name, Source.Id);
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Base;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:apparition",
|
||||
InnerType = "apparition",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Apparitions",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal partial class ApparitionProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Animist";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Apparition";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
AddSpells(Input.GetRequired<string>("spell_markdown"));
|
||||
AddFocal(Entity.Description);
|
||||
AddTrainings(Input.GetRequired<string>("skill_markdown"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавление заклинания сосуда.
|
||||
/// </summary>
|
||||
/// <param name="description"></param>
|
||||
public void AddFocal(string description)
|
||||
{
|
||||
Match match = VesselSpellMarkdownRegex().Match(description);
|
||||
string aonprdId = $"spell-{match.Groups[1].Value}";
|
||||
|
||||
Entity entity = Context
|
||||
.EntityExternals.Where(x => x.ExternalId == aonprdId)
|
||||
.Select(x => x.Entity)
|
||||
.First();
|
||||
|
||||
Object.Entities.Add(entity);
|
||||
}
|
||||
|
||||
//protected override string GetDescription() =>
|
||||
// base.GetDescription()
|
||||
// + AddedDescription(["skill_markdown", "spell_markdown", "summary_markdown"]);
|
||||
|
||||
[GeneratedRegex(@"\*\*Vessel Spell\*\* \[.*?\]\(/Spells\.aspx\?ID=(\d+)\)")]
|
||||
private static partial Regex VesselSpellMarkdownRegex();
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Base;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:arcane-school",
|
||||
InnerType = "arcane-school",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Arcane Schools",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class ArcaneSchoolProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Wizard";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Arcane School";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
AddSpells(Input.GetRequired<string>("spell_markdown"));
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:arcane-thesis",
|
||||
InnerType = "arcane-thesis",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Arcane Theses",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class ArcaneThesisProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Wizard";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Arcane Thesis";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:bloodline",
|
||||
InnerType = "bloodline",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Bloodlines",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class BloodlineProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Sorcerer";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Bloodline";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
AddSpells(Input.GetRequired<string>("spell_markdown"));
|
||||
|
||||
Object.Extra = GenerateJsonString("tradition");
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:cause",
|
||||
InnerType = "cause",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Causes",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class CauseProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Champion";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Cause";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
Object.Extra = GenerateJsonString("alignment");
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:conscious-mind",
|
||||
InnerType = "conscious-mind",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Conscious Minds",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class ConsciousMindProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Psychic";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Conscious Mind";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
AddSpells(Input.GetRequired<string>("spell_markdown"));
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:doctrine",
|
||||
InnerType = "doctrine",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Doctrines",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class DoctrineProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Cleric";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Doctrine";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:druidic-order",
|
||||
InnerType = "druidic-order",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Druidic Orders",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class DruidicOrderProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Druid";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Druidic Order";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:eidolon",
|
||||
InnerType = "eidolon",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Eidolons",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class EidolonProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Summoner";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Eidolon";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
AddTrainings(Input.GetRequired<string>("skill_markdown"));
|
||||
|
||||
Object.Extra = GenerateJsonString(
|
||||
"alignment",
|
||||
"language_markdown",
|
||||
"size",
|
||||
"tradition",
|
||||
"speed"
|
||||
);
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:element",
|
||||
InnerType = "element",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Elements",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class ElementProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Kineticist";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Element";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
Object.Extra = GenerateJsonString("element");
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Collection;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Base;
|
||||
using Pf2e.Database.Model.Common;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:epithet",
|
||||
InnerType = "epithet",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Epithets",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class EpithetProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Exemplar";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Epithet";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
Object.Extra = GenerateJsonString("level", "type");
|
||||
// No additional processing needed
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
// TODO: Придумать логику для обработки под-архетипа (Hellknight Order)
|
||||
|
||||
//[ProcessorCollection(
|
||||
// "aonprd:hellknight-order",
|
||||
// InnerType = "hellknight-order",
|
||||
// CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
// Description = "Hellknight Orders",
|
||||
// Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
//)]
|
||||
//[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class HellknightOrderProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Hellknight";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Order";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
Object.Extra = GenerateJsonString("favored_weapon_markdown");
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:hunters-edge",
|
||||
InnerType = "hunters-edge",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Hunter's Edges",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class HuntersEdgeProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Ranger";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Hunter's Edge";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:hybrid-study",
|
||||
InnerType = "hybrid-study",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Hybrid Studies",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class HybridStudyProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Magus";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Hybrid Study";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:ikon",
|
||||
InnerType = "ikon",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Ikon",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class IkonProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Exemplar";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Ikon";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
Object.Extra = GenerateJsonString("type", "usage_markdown");
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:implement",
|
||||
InnerType = "implement",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Implements",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class ImplementProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Thaumaturge";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Implement";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:innovation",
|
||||
InnerType = "innovation",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Innovations",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class InnovationProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Inventor";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Innovation";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:instinct",
|
||||
InnerType = "instinct",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Instincts",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class InstinctProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Barbarian";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Instinct";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:lesson",
|
||||
InnerType = "lesson",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Lessons",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class LessonProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Witch";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Lesson";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
Object.Extra = GenerateJsonString("lesson_type");
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:methodology",
|
||||
InnerType = "methodology",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Methodologies",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class MethodologyProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Investigator";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Methodology";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:muse",
|
||||
InnerType = "muse",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Muses",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class MuseProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Bard";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Muse";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:mystery",
|
||||
InnerType = "mystery",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Mysteries",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class MysteryProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Oracle";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Mystery";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
AddSpells(Input.GetRequired<string>("spell_markdown"));
|
||||
|
||||
// TODO: Добавть проверку на упоминание Lore в skill_markdown
|
||||
// AddTrainings(Input.GetRequired<string>("skill_markdown"));
|
||||
|
||||
Object.Extra = GenerateJsonString("domain", "skill_markdown");
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Collection;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Base;
|
||||
using Pf2e.Database.Model.Common;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:patron",
|
||||
InnerType = "patron",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Patrons",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class PatronProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Witch";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Patron";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
AddTrainings(Input.GetRequired<string>("skill_markdown"));
|
||||
|
||||
Object.Extra = GenerateJsonString("tradition", "skill_markdown");
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:practice",
|
||||
InnerType = "practice",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Practices",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class PracticeProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Animist";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Practice";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:racket",
|
||||
InnerType = "racket",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Rackets",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class RacketProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Rogue";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Racket";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:research-field",
|
||||
InnerType = "research-field",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Research Fields",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class ResearchFieldProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Alchemist";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Research Field";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:style",
|
||||
InnerType = "style",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Styles",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class StyleProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Swashbuckler";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Style";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Definitions;
|
||||
using Pf2e.Scrapper.Processors.Factory;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Base;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorFactory(
|
||||
"aonprd:subclass-group",
|
||||
ProcessorType = typeof(SubclassGroupProcessor),
|
||||
Description = "Группы подклассов",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses,
|
||||
Parallel = true
|
||||
)]
|
||||
[ProcessorDependencies(
|
||||
["aonprd:trait", "aonprd:source", "aonprd:class", "aonprd:spell", "aonprd:skill"]
|
||||
)]
|
||||
internal class SubclassGroupProcessorFactory(
|
||||
IServiceProvider serviceProvider,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractProcessorFactory
|
||||
{
|
||||
public IServiceProvider ServiceProvider { get; } = serviceProvider;
|
||||
public AonprdBuilderGlobals Globals { get; } = globals;
|
||||
|
||||
public override int Count() => Globals.SubclassGroups.Count;
|
||||
|
||||
public override IEnumerable<Tuple<string, IProcessor>> GetEnumerator()
|
||||
{
|
||||
foreach ((string key, string value) in Globals.SubclassGroups)
|
||||
{
|
||||
var processor =
|
||||
value == "_null"
|
||||
? ActivatorUtilities.CreateInstance<SubclassGroupProcessor>(
|
||||
ServiceProvider,
|
||||
key
|
||||
)
|
||||
: ActivatorUtilities.CreateInstance<SubclassGroupProcessor>(
|
||||
ServiceProvider,
|
||||
key,
|
||||
value
|
||||
);
|
||||
|
||||
yield return new($"{key} -> {value}", processor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class SubclassGroupProcessor(string groupName, string? className, DatabaseHelper helper)
|
||||
: IProcessor
|
||||
{
|
||||
public string GroupName { get; } = groupName;
|
||||
public string? ClassName { get; } = className;
|
||||
public DatabaseHelper Helper { get; } = helper;
|
||||
|
||||
public SubclassGroupProcessor(string groupName, DatabaseHelper helper)
|
||||
: this(groupName, null, helper) { }
|
||||
|
||||
public Pf2eDbContext Context { get; } = new();
|
||||
|
||||
public void Process()
|
||||
{
|
||||
Class? cl = ClassName is not null
|
||||
? Context.Classes.FirstOrDefault(c =>
|
||||
Pf2eDbContext.LocaleSearch(c.Entity.Name, ClassName)
|
||||
)
|
||||
: null;
|
||||
|
||||
int id;
|
||||
lock (Helper.IdLock)
|
||||
{
|
||||
id = Helper.NextEntityId;
|
||||
}
|
||||
|
||||
Entity groupEntity = new()
|
||||
{
|
||||
Id = id,
|
||||
Type = EntityType.SubclassGroup,
|
||||
Img = "",
|
||||
Description = "",
|
||||
Rarity = EntityRarity.Common,
|
||||
IsTranslated = false,
|
||||
IsChecked = false,
|
||||
Name = { [LocaleType.English] = GroupName },
|
||||
Slug = Helper.GenerateSlug(GroupName),
|
||||
};
|
||||
|
||||
Context.Entities.Add(groupEntity);
|
||||
|
||||
SubclassGroup group = new() { Entity = groupEntity, Class = cl };
|
||||
Context.SubclassGroups.Add(group);
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
Context.SaveChanges();
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:subconscious-mind",
|
||||
InnerType = "subconscious-mind",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Subconscious Minds",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class SubconsciousMindProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Psychic";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Subconscious Mind";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject()
|
||||
{
|
||||
Object.Extra = GenerateJsonString("attribute");
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:tenet",
|
||||
InnerType = "tenet",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Tenets",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class TenetProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Champion";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Tenet";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:way",
|
||||
InnerType = "way",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Ways",
|
||||
Group = ProcessorGroupEnum.AonprdSubclasses
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:subclass-group"])]
|
||||
internal class WayProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractSubclassProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override Subclass Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ClassName => "Gunslinger";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string GroupName => "Way";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void ProcessObject() { }
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:action",
|
||||
InnerType = "action",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Действия",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:trait", "aonprd:source"])]
|
||||
internal partial class ActionProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Action;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Database.Model.Structure.Action Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Actions.Add(Object);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
Check();
|
||||
|
||||
base.Process();
|
||||
|
||||
Object.Actions = Input.EnumOptional("actions", ActionEnum.Passive);
|
||||
Object.Extra = GenerateJsonString("school");
|
||||
}
|
||||
|
||||
public override void Check()
|
||||
{
|
||||
base.Check();
|
||||
|
||||
if (Input.GetRequired<string>("markdown").StartsWith("**Activate"))
|
||||
{
|
||||
throw new SkipItemException(Input.GetRequired<string>("name"), "activating action");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string[] AddedDescriptionPaths() =>
|
||||
[
|
||||
"cost_markdown",
|
||||
"trait_markdown",
|
||||
"source_markdown",
|
||||
"search_markdown",
|
||||
"requirement_markdown",
|
||||
"trigger_markdown",
|
||||
"summary_markdown",
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Collection;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:ancestry",
|
||||
InnerType = "ancestry",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Родословные",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:trait", "aonprd:source", "aonprd:language"])]
|
||||
internal class AncestryProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Ancestry;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Ancestry Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Ancestries.Add(Object);
|
||||
|
||||
public override void Check()
|
||||
{
|
||||
base.Check();
|
||||
|
||||
if (Input.GetRequired<string>("type") != "Ancestry")
|
||||
{
|
||||
throw new SkipItemException(Input.GetRequired<string>("name"), "не родословная");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
|
||||
Object.Size = Input
|
||||
.GetRequired<JArray>("size")
|
||||
.Select(t => Input.Enum<SizeEnum>(t.ToString()))
|
||||
.ToArray();
|
||||
|
||||
string hp = Input.GetRequired<string>("hp_raw");
|
||||
Object.Hp = Convert.ToInt32((hp != "") ? hp : "0");
|
||||
|
||||
Object.Speed = Convert.ToInt32(Input.GetOptional<int>("speed.land"));
|
||||
|
||||
Object.VisionEnum = Input.EnumOptional("vision", VisionEnum.Normal);
|
||||
|
||||
AddBoosts("attribute", true);
|
||||
AddBoosts("attribute_flaw", false);
|
||||
|
||||
// TODO - import languages from Foundry!
|
||||
// ProcessLanguages();
|
||||
}
|
||||
|
||||
protected void AddBoosts(string path, bool isBoost)
|
||||
{
|
||||
List<string> boosts =
|
||||
Input.GetOptional<JArray>(path)?.ToArray().Select(t => t.ToString()).ToList() ?? [];
|
||||
|
||||
if (boosts.Contains("Two free ability boosts"))
|
||||
{
|
||||
boosts.Remove("Two free ability boosts");
|
||||
boosts.Add("Free");
|
||||
boosts.Add("Free");
|
||||
}
|
||||
|
||||
foreach (string boost in boosts)
|
||||
{
|
||||
Context.AncestryBoosts.Add(
|
||||
new()
|
||||
{
|
||||
Ancestry = Object,
|
||||
Boost = isBoost,
|
||||
Value = Input.Enum<AttributeValues>(boost),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Collection;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:archetype",
|
||||
InnerType = "archetype",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Архетипы",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:trait", "aonprd:source"])]
|
||||
internal class ArchetypeProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Archetype;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Archetype Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Archetypes.Add(Object);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
|
||||
Object.Level = Input.GetOptional<int>("level");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string[] AddedDescriptionPaths() =>
|
||||
["prerequisite_markdown", "requirement_markdown", "summary_markdown"];
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Collection;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Pf2e.Database.Model.Structure.BackgroundRelation;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:background",
|
||||
InnerType = "background",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Предыстории",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:trait", "aonprd:source"])]
|
||||
internal class BackgroundProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Background;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Background Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Backgrounds.Add(Object);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
|
||||
foreach (JToken token in Input.GetOptional<JArray>("attribute") ?? [])
|
||||
{
|
||||
BackgroundBoost boost = new()
|
||||
{
|
||||
Background = Object,
|
||||
Attribute = Input.Enum<AttributeValues>(token.ToString()),
|
||||
};
|
||||
|
||||
Object.BackgroundBoosts.Add(boost);
|
||||
Context.BackgroundBoosts.Add(boost);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string[] AddedDescriptionPaths() =>
|
||||
["feat_markdown", "summary_markdown", "skill_markdown", "prerequisite_markdown"];
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Common;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Pf2e.Database.Model.Structure.ClassRelation;
|
||||
using static System.Text.RegularExpressions.Regex;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:class",
|
||||
InnerType = "class",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Классы",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:trait", "aonprd:source", "aonprd:skill"])]
|
||||
internal partial class ClassProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Class;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Class Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Classes.Add(Object);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
|
||||
Object.Hp = Convert.ToInt32(Input.GetRequired<string>("hp_raw"));
|
||||
|
||||
AttributeValues[] attributes = Input
|
||||
.GetRequired<JArray>("attribute")
|
||||
.Select(token => Input.Enum<AttributeValues>(token.ToString()))
|
||||
.ToArray();
|
||||
|
||||
foreach (AttributeValues attribute in attributes)
|
||||
{
|
||||
ClassKeyAttribute classKeyAttribute = new() { Class = Object, Value = attribute };
|
||||
|
||||
Context.ClassKeyAbilities.Add(classKeyAttribute);
|
||||
Object.ClassKeyAbilities.Add(classKeyAttribute);
|
||||
}
|
||||
|
||||
ClassTraining[] classTrainings =
|
||||
[
|
||||
.. ProcessTraining(
|
||||
Input.GetRequired<JArray>("attack_proficiency"),
|
||||
TrainingType.Weapon
|
||||
),
|
||||
.. ProcessTraining(
|
||||
Input.GetRequired<JArray>("defense_proficiency"),
|
||||
TrainingType.Armor
|
||||
),
|
||||
.. GetSkillTrainings(),
|
||||
.. GetSaveTrainings(),
|
||||
];
|
||||
|
||||
foreach (ClassTraining classTraining in classTrainings)
|
||||
{
|
||||
Context.ClassTrainings.Add(classTraining);
|
||||
Object.ClassTrainings.Add(classTraining);
|
||||
}
|
||||
|
||||
JArray tradition = Input.GetOptional<JArray>("tradition") ?? [];
|
||||
|
||||
switch (tradition.Count)
|
||||
{
|
||||
case 0:
|
||||
Object.Tradition = SpellTradition.None;
|
||||
break;
|
||||
case 1:
|
||||
Object.Tradition = Input.Enum<SpellTradition>(tradition[0].ToString());
|
||||
break;
|
||||
default:
|
||||
Object.Tradition = SpellTradition.All;
|
||||
break;
|
||||
}
|
||||
|
||||
ProcessClassTrait();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение коллекции обучений, связанных с классом.
|
||||
/// </summary>
|
||||
/// <returns>Коллекция обучения.</returns>
|
||||
protected ICollection<ClassTraining> GetSkillTrainings()
|
||||
{
|
||||
List<string> skillNames = Input
|
||||
.GetRequired<JArray>("skill_proficiency")
|
||||
.Select(token => token.ToString())
|
||||
.ToList();
|
||||
|
||||
Training[] skills = Context
|
||||
.Trainings.Where(t => Pf2eDbContext.LocaleSearchArray(t.Name, skillNames))
|
||||
.ToArray();
|
||||
|
||||
return skills
|
||||
.Select(skill => new ClassTraining()
|
||||
{
|
||||
Class = Object,
|
||||
Training = skill,
|
||||
Rank = TrainingRank.Trained,
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка массива со списком обучений.
|
||||
/// </summary>
|
||||
/// <param name="array">JSON-массив обучений.</param>
|
||||
/// <param name="type">Тип обучения.</param>
|
||||
/// <returns>Коллекция обучений.</returns>
|
||||
protected ICollection<ClassTraining> ProcessTraining(JArray array, TrainingType type)
|
||||
{
|
||||
const string pattern = @"^(.*?) in\s+(?:the)?\s*(.*)$";
|
||||
List<ClassTraining> trainings = [];
|
||||
|
||||
foreach (string value in array.Select(token => token.ToString()))
|
||||
{
|
||||
MatchCollection m = Matches(value, pattern);
|
||||
|
||||
if (m.Count == 0)
|
||||
{
|
||||
throw new($"Can't parse training string '{value}'");
|
||||
}
|
||||
|
||||
TrainingRank rank = Input.Enum<TrainingRank>(m[0].Groups[1].Value);
|
||||
|
||||
foreach (string part in GetTrainingString(m[0].Groups[2].Value))
|
||||
{
|
||||
Training? training = Context.Trainings.FirstOrDefault(t =>
|
||||
Pf2eDbContext.LocaleSearch(t.Name, part) && t.Type == type
|
||||
);
|
||||
|
||||
if (training == null)
|
||||
{
|
||||
training = new()
|
||||
{
|
||||
Name = new() { [LocaleType.English] = part },
|
||||
Type = type,
|
||||
};
|
||||
|
||||
Context.Trainings.Add(training);
|
||||
}
|
||||
|
||||
ClassTraining classTraining = new()
|
||||
{
|
||||
Class = Object,
|
||||
Training = training,
|
||||
Rank = rank,
|
||||
};
|
||||
|
||||
trainings.Add(classTraining);
|
||||
}
|
||||
}
|
||||
|
||||
return trainings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение коллекции названий обучений из строкового представления из Архивов Нефиса.
|
||||
/// </summary>
|
||||
/// <param name="value">Строковое представление обучений из Архивов Нефиса.</param>
|
||||
/// <returns>Коллекция названий обучений.</returns>
|
||||
protected ICollection<string> GetTrainingString(string value)
|
||||
{
|
||||
return value.StartsWith("favored weapon of your deity") ? ["Favored weapon of your deity"]
|
||||
: value == "simple and martial weapons" ? ["Simple weapon", "Martial weapon"]
|
||||
: TrainingStringSeparatorRegex()
|
||||
.Split(value)
|
||||
.Where(s => s != "")
|
||||
.Select(s => string.Concat(s[0].ToString().ToUpper(), s.AsSpan(1)))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение CLR-представления обучений спасброскам.
|
||||
/// </summary>
|
||||
/// <returns>Коллекция обучений.</returns>
|
||||
protected ICollection<ClassTraining> GetSaveTrainings()
|
||||
{
|
||||
Dictionary<string, Training> result = Context
|
||||
.Trainings.Where(t => t.Type == TrainingType.Save)
|
||||
.ToDictionary(t => t.Name[LocaleType.English]);
|
||||
|
||||
foreach (string name in new[] { "Will", "Fortitude", "Reflex", "Perception" })
|
||||
{
|
||||
if (result.ContainsKey(name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Training training = new()
|
||||
{
|
||||
Name = new() { [LocaleType.English] = name },
|
||||
Type = (name == "Perception") ? TrainingType.Perception : TrainingType.Save,
|
||||
};
|
||||
|
||||
result.Add(name, training);
|
||||
Context.Trainings.Add(training);
|
||||
}
|
||||
|
||||
return result
|
||||
.Select(pair =>
|
||||
{
|
||||
ClassTraining classTraining = new()
|
||||
{
|
||||
Class = Object,
|
||||
Training = pair.Value,
|
||||
Rank = Input.EnumRequired<TrainingRank>($"{pair.Key.ToLower()}_proficiency"),
|
||||
};
|
||||
|
||||
return classTraining;
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Объявление соотеветсвующего классу признака классовым.
|
||||
/// </summary>
|
||||
protected void ProcessClassTrait()
|
||||
{
|
||||
Trait? classTrait = Context.Traits.FirstOrDefault(t => t.Entity.Name == Entity.Name);
|
||||
|
||||
if (classTrait is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
classTrait.Type = TraitType.Class;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение регулярного выражения для разделения строки строкового представления обучений.
|
||||
/// </summary>
|
||||
/// <returns>Регулярное выражение.</returns>
|
||||
[GeneratedRegex(@"\s*(?:,|and)\s*")]
|
||||
protected static partial Regex TrainingStringSeparatorRegex();
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:deity-category",
|
||||
InnerType = "deity-category",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Категории божеств",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
internal class DeityCategoryProcessor(
|
||||
ProcessorInput input,
|
||||
StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.DeityCategory;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override DeityCategory Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.DeityCategories.Add(Object);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
|
||||
// Обработка описания категории
|
||||
ProcessDescription();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка описания категории.
|
||||
/// </summary>
|
||||
private void ProcessDescription()
|
||||
{
|
||||
// Получаем markdown с описанием из summary_markdown или другого поля
|
||||
// В данных deity-category.yaml нет summary_markdown, используем пустую строку
|
||||
string descriptionMarkdown = string.Empty;
|
||||
|
||||
// Преобразуем markdown в текст (можно добавить более сложную обработку)
|
||||
// Пока просто сохраняем как есть
|
||||
Object.Description[LocaleType.English] = descriptionMarkdown;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Common;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Pf2e.Database.Model.Structure.DeityRelation;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:deity",
|
||||
InnerType = "deity",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Божества",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:domain", "aonprd:spell", "aonprd:trait", "aonprd:source"])]
|
||||
internal partial class DeityProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Deity;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Deity Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Deities.Add(Object);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
|
||||
// Установка категории божества
|
||||
string categoryName = Input.GetRequired<string>("deity_category");
|
||||
Object.Category = categoryName;
|
||||
|
||||
// Связываем с сущностью категории
|
||||
ProcessCategory(categoryName);
|
||||
|
||||
ProcessFonts();
|
||||
|
||||
// Обработка атрибутов
|
||||
ProcessAttributes();
|
||||
|
||||
// Обработка доменов
|
||||
ProcessDomains();
|
||||
|
||||
// Обработка заклинаний
|
||||
ProcessSpells();
|
||||
|
||||
// Обработка оружия
|
||||
ProcessWeapons();
|
||||
|
||||
// Обработка навыков
|
||||
ProcessSkills();
|
||||
|
||||
// Обработка текстов описания
|
||||
ProcessTexts();
|
||||
|
||||
// Обработка освящения - в Foundry!
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void AddTraits()
|
||||
{
|
||||
// У божеств нет признаков. Не знаю, зачем они на Архивах.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка божественной силы.
|
||||
/// </summary>
|
||||
private void ProcessFonts()
|
||||
{
|
||||
JArray fonts = Input.GetOptional<JArray>("divine_font") ?? [];
|
||||
|
||||
switch (fonts.Count)
|
||||
{
|
||||
case 0:
|
||||
Object.Fonts = DeityFonts.None;
|
||||
return;
|
||||
|
||||
// Если есть и Heal, и Harm
|
||||
case 2:
|
||||
Object.Fonts = DeityFonts.Any;
|
||||
return;
|
||||
|
||||
default:
|
||||
{
|
||||
// Определяем тип по первому элементу
|
||||
string font = fonts[0].ToString();
|
||||
Object.Fonts = Input.Enum<DeityFonts>(font);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка атрибутов божества.
|
||||
/// </summary>
|
||||
private void ProcessAttributes()
|
||||
{
|
||||
JArray attributes = Input.GetOptional<JArray>("attribute") ?? [];
|
||||
foreach (JToken token in attributes)
|
||||
{
|
||||
AttributeValues attribute = Input.Enum<AttributeValues>(token.ToString());
|
||||
Object.DeityAttributes.Add(new() { Deity = Object, Attribute = attribute });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка доменов божества.
|
||||
/// </summary>
|
||||
private void ProcessDomains()
|
||||
{
|
||||
// Обработка основных доменов
|
||||
string primaryDomainsMarkdown = Input.GetRequired<string>("domain_primary_markdown");
|
||||
ProcessDomainMarkdown(primaryDomainsMarkdown, true);
|
||||
|
||||
// Обработка альтернативных доменов
|
||||
string alternateDomainsMarkdown = Input.GetRequired<string>("domain_alternate_markdown");
|
||||
ProcessDomainMarkdown(alternateDomainsMarkdown, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка markdown-строки с доменами.
|
||||
/// </summary>
|
||||
/// <param name="markdown">Markdown-строка с доменами.</param>
|
||||
/// <param name="isPrimary">Флаг, указывающий, являются ли домены основными.</param>
|
||||
private void ProcessDomainMarkdown(string markdown, bool isPrimary)
|
||||
{
|
||||
// Разделяем markdown на отдельные ссылки
|
||||
MatchCollection matches = MarkdownLinkRegex().Matches(markdown);
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
string domainName = match.Groups[1].Value;
|
||||
|
||||
// Ищем домен в базе данных
|
||||
Domain? domain = Context.Domains.FirstOrDefault(d =>
|
||||
Pf2eDbContext.LocaleSearch(d.Entity.Name, domainName)
|
||||
);
|
||||
|
||||
if (domain != null)
|
||||
{
|
||||
Object.DeityDomains.Add(
|
||||
new()
|
||||
{
|
||||
Deity = Object,
|
||||
Domain = domain,
|
||||
IsPrimary = isPrimary,
|
||||
Value = domainName,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка заклинаний божества.
|
||||
/// </summary>
|
||||
private void ProcessSpells()
|
||||
{
|
||||
string spellsMarkdown = Input.GetRequired<string>("spell_markdown");
|
||||
MatchCollection matches = MarkdownLinkRegex().Matches(spellsMarkdown);
|
||||
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
string spellName = match.Groups[1].Value;
|
||||
|
||||
// Ищем заклинание в базе данных
|
||||
Spell? spell = Context.Spells.FirstOrDefault(s =>
|
||||
Pf2eDbContext.LocaleSearch(s.Entity.Name, spellName)
|
||||
);
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
Object.DeitySpells.Add(
|
||||
new()
|
||||
{
|
||||
Deity = Object,
|
||||
Spell = spell,
|
||||
Level = spell.Level,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка оружия божества.
|
||||
/// </summary>
|
||||
private void ProcessWeapons()
|
||||
{
|
||||
string weaponsMarkdown = Input.GetRequired<string>("favored_weapon_markdown");
|
||||
MatchCollection matches = MarkdownLinkRegex().Matches(weaponsMarkdown);
|
||||
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
string weaponName = match.Groups[1].Value;
|
||||
Object.DeityWeapons.Add(new() { Deity = Object, Weapon = weaponName });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка навыков божества.
|
||||
/// </summary>
|
||||
private void ProcessSkills()
|
||||
{
|
||||
string skillsMarkdown = Input.GetRequired<string>("skill_markdown");
|
||||
MatchCollection matches = MarkdownLinkRegex().Matches(skillsMarkdown);
|
||||
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
string skillName = match.Groups[1].Value;
|
||||
|
||||
// Ищем навык в базе данных
|
||||
Training? training = Context.Trainings.FirstOrDefault(t =>
|
||||
Pf2eDbContext.LocaleSearch(t.Name, skillName)
|
||||
);
|
||||
|
||||
if (training != null)
|
||||
{
|
||||
Object.Skills.Add(training);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка категории божества.
|
||||
/// </summary>
|
||||
/// <param name="categoryName">Название категории.</param>
|
||||
private void ProcessCategory(string categoryName)
|
||||
{
|
||||
// Ищем категорию в базе данных
|
||||
DeityCategory? category = Context.DeityCategories.FirstOrDefault(dc =>
|
||||
Pf2eDbContext.LocaleSearch(dc.Entity.Name, categoryName)
|
||||
);
|
||||
|
||||
if (category != null)
|
||||
{
|
||||
Object.CategoryId = category.Id;
|
||||
Object.CategoryEntity = category;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка текстов описания божества.
|
||||
/// </summary>
|
||||
private void ProcessTexts()
|
||||
{
|
||||
Object.Edicts[LocaleType.English] = Input.GetRequired<string>("edict");
|
||||
Object.Anathema[LocaleType.English] = Input.GetRequired<string>("anathema");
|
||||
Object.ReligiousSymbol[LocaleType.English] = Input.GetOptional<string>(
|
||||
"religious_symbol",
|
||||
""
|
||||
);
|
||||
Object.SacredAnimal[LocaleType.English] = Input.GetOptional<string>("sacred_animal", "");
|
||||
Object.AreaOfConcern[LocaleType.English] = Input.GetOptional<string>(
|
||||
"area_of_concern_raw",
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Регулярное выражение для извлечения названия из markdown-ссылки.
|
||||
/// </summary>
|
||||
/// <returns>Скомпилированное регулярное выражение.</returns>
|
||||
[GeneratedRegex(@"\[([^\]]+)\]\([^)]+\)")]
|
||||
private static partial Regex MarkdownLinkRegex();
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:domain",
|
||||
InnerType = "domain",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Домены",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:spell"])]
|
||||
internal partial class DomainProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Domain;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Domain Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Domains.Add(Object);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
|
||||
// Обработка заклинаний домена
|
||||
ProcessDomainSpells();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка заклинаний, связанных с доменом.
|
||||
/// </summary>
|
||||
private void ProcessDomainSpells()
|
||||
{
|
||||
// Обработка основного заклинания домена
|
||||
string domainSpellMarkdown = Input.GetRequired<string>("domain_spell_markdown");
|
||||
Object.DomainSpellId = GetSpellIdFromMarkdown(domainSpellMarkdown);
|
||||
|
||||
// Обработка продвинутого заклинания домена
|
||||
string advancedDomainSpellMarkdown = Input.GetRequired<string>(
|
||||
"advanced_domain_spell_markdown"
|
||||
);
|
||||
Object.AdvancedDomainSpellId = GetSpellIdFromMarkdown(advancedDomainSpellMarkdown);
|
||||
|
||||
// Обработка апокрифического заклинания (если есть)
|
||||
string? apocryphalSpellMarkdown = Input.GetOptional<string>("apocryphal_spell_markdown");
|
||||
if (!string.IsNullOrEmpty(apocryphalSpellMarkdown))
|
||||
{
|
||||
Object.ApocryphalSpellId = GetSpellIdFromMarkdown(apocryphalSpellMarkdown);
|
||||
}
|
||||
|
||||
// Обработка продвинутого апокрифического заклинания (если есть)
|
||||
string? advancedApocryphalSpellMarkdown = Input.GetOptional<string>(
|
||||
"advanced_apocryphal_spell_markdown"
|
||||
);
|
||||
if (!string.IsNullOrEmpty(advancedApocryphalSpellMarkdown))
|
||||
{
|
||||
Object.AdvancedApocryphalSpellId = GetSpellIdFromMarkdown(
|
||||
advancedApocryphalSpellMarkdown
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение идентификатора заклинания из markdown-строки.
|
||||
/// </summary>
|
||||
/// <param name="markdown">Markdown-строка с информацией о заклинании.</param>
|
||||
/// <returns>Идентификатор заклинания.</returns>
|
||||
private int GetSpellIdFromMarkdown(string markdown)
|
||||
{
|
||||
// Используем регулярное выражение для извлечения названия заклинания
|
||||
// Формат: [Название заклинания](/Spells.aspx?ID=XXX)
|
||||
Match match = MarkdownLinkRegex().Match(markdown);
|
||||
|
||||
if (!match.Success)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid markdown format: {markdown}");
|
||||
}
|
||||
|
||||
string spellName = match.Groups[1].Value;
|
||||
|
||||
// Поиск заклинания в базе данных
|
||||
Spell? spell = Context.Spells.FirstOrDefault(s =>
|
||||
Pf2eDbContext.LocaleSearch(s.Entity.Name, spellName)
|
||||
);
|
||||
|
||||
if (spell == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Spell '{spellName}' not found in database");
|
||||
}
|
||||
|
||||
return spell.Id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Регулярное выражение для извлечения названия из markdown-ссылки.
|
||||
/// </summary>
|
||||
/// <returns>Скомпилированное регулярное выражение.</returns>
|
||||
[GeneratedRegex(@"\[([^\]]+)\]\([^)]+\)")]
|
||||
private static partial Regex MarkdownLinkRegex();
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:feat",
|
||||
InnerType = "feat",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Черты",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:trait", "aonprd:source", "aonprd:archetype"])]
|
||||
internal class FeatProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Feat;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Feat Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Feats.Add(Object);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
|
||||
Object.Level = Input.GetRequired<int>("level");
|
||||
|
||||
Object.Category = Entity.Traits.Any(t => t.Type == TraitType.Class)
|
||||
? FeatCategory.Class
|
||||
: FeatCategory.Uncategorized;
|
||||
|
||||
Object.Actions = Input.EnumOptional("actions", ActionEnum.Unknown);
|
||||
|
||||
Object.Extra = GenerateJsonString(
|
||||
"archetype",
|
||||
"element",
|
||||
"heighten",
|
||||
"heighten_group",
|
||||
"heighten_level",
|
||||
"school",
|
||||
"frequency"
|
||||
);
|
||||
|
||||
string[] archetypeStrings =
|
||||
Input.GetOptional<JArray>("archetype")?.Select(t => t.ToString()).ToArray() ?? [];
|
||||
|
||||
Archetype[] archetypes = Context
|
||||
// ReSharper disable once EntityFramework.UnsupportedServerSideFunctionCall
|
||||
.Archetypes.Where(a => Pf2eDbContext.LocaleSearchArray(a.Entity.Name, archetypeStrings))
|
||||
// .Where(a => archetypeStrings.Contains(a.Entity.Group.ToString()))
|
||||
.ToArray();
|
||||
|
||||
if (archetypes.Length != 0)
|
||||
{
|
||||
Object.Category = FeatCategory.Archetype;
|
||||
}
|
||||
|
||||
foreach (Archetype archetype in archetypes)
|
||||
{
|
||||
Object.Archetypes.Add(archetype);
|
||||
|
||||
if (Entity.Name.Any(l => l.Value.Contains("Dedication")))
|
||||
{
|
||||
archetype.DedicationFeat = Object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string GetDescription() =>
|
||||
base.GetDescription()
|
||||
+ AddedDescription(
|
||||
[
|
||||
"cost_markdown",
|
||||
"feat_markdown",
|
||||
"summary_markdown",
|
||||
"prerequisite_markdown",
|
||||
"requirement_markdown",
|
||||
"trigger_markdown",
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:heritage",
|
||||
InnerType = "heritage",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Наследства",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:ancestry"])]
|
||||
internal class HeritageProcessor(
|
||||
ProcessorInput input,
|
||||
StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Heritage;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Heritage Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Heritages.Add(Object);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:language",
|
||||
InnerType = "language",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Языки",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:trait", "aonprd:source"])]
|
||||
internal class LanguageProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Language;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Language Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Languages.Add(Object);
|
||||
}
|
||||
@@ -0,0 +1,408 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Pf2e.Database.Model.Structure.RitualRelation;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:ritual",
|
||||
InnerType = "ritual",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Ритуалы",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:trait", "aonprd:source", "aonprd:skill"])]
|
||||
internal partial class RitualProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Ritual;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Ritual Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Rituals.Add(Object);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
|
||||
Object.Level = Input.GetRequired<int>("level");
|
||||
Object.Duration = Input.GetOptional("duration", -1);
|
||||
|
||||
Object.Range = Input.GetOptional("range", -1);
|
||||
Object.RangeString = Input.GetOptionalLocale("range_raw", LocaleType.English);
|
||||
|
||||
Object.CastTime = CalculateCastTime(Input.GetRequired<string>("actions"));
|
||||
|
||||
Object.Cost = Input.GetOptionalLocale("cost_markdown", LocaleType.English);
|
||||
|
||||
Object.Target = Input.GetOptionalLocale("target_markdown", LocaleType.English);
|
||||
Object.Requirement = Input.GetOptionalLocale("requirement_markdown", LocaleType.English);
|
||||
|
||||
Object.Elements = (Input.GetOptional<JArray>("element") ?? [])
|
||||
.Select(token => Input.Enum<ElementEnum>(token.ToString()))
|
||||
.ToArray();
|
||||
|
||||
ProcessArea();
|
||||
|
||||
ProcessPrimaryChecks();
|
||||
ProcessSecondaryChecks();
|
||||
|
||||
ProcessSecondaryCasters();
|
||||
}
|
||||
|
||||
private int CalculateCastTime(string value)
|
||||
{
|
||||
string[] parts = value.Trim().ToLower().Split(" ");
|
||||
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
throw new($"Can't determine cast time of \"{value}\"");
|
||||
}
|
||||
|
||||
int number = int.Parse(parts[0]);
|
||||
|
||||
string unit = parts[1].ToLower();
|
||||
int unitSeconds = unit switch
|
||||
{
|
||||
"hour" => 3600,
|
||||
"hours" => 3600,
|
||||
"day" => 86400,
|
||||
"days" => 86400,
|
||||
"week" => 7 * 86400,
|
||||
"weeks" => 7 * 86400,
|
||||
_ => throw new($"Can't determine cast time of \"{value}\""),
|
||||
};
|
||||
|
||||
return number * unitSeconds;
|
||||
}
|
||||
|
||||
private void ProcessArea()
|
||||
{
|
||||
string? areaRaw = Input.GetOptional<string>("area_raw");
|
||||
|
||||
if (string.IsNullOrEmpty(areaRaw))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string areaType = Input.GetRequired<string[]>("area_type")[0];
|
||||
RitualArea ritualArea = new()
|
||||
{
|
||||
Ritual = Object,
|
||||
Type = Input.Enum<SpellAreaType>(areaType),
|
||||
Details = new() { [LocaleType.English] = areaRaw },
|
||||
};
|
||||
|
||||
Object.Area = ritualArea;
|
||||
Context.RitualAreas.Add(ritualArea);
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, string> _castersCleanup = new()
|
||||
{
|
||||
[", up to a maximum of "] = "-",
|
||||
[" or more"] = "-999",
|
||||
[" (or more)"] = "-999",
|
||||
["up to "] = "0-",
|
||||
[" to "] = "-",
|
||||
["at least 1"] = "1-999",
|
||||
};
|
||||
|
||||
private void ProcessSecondaryCasters()
|
||||
{
|
||||
string? input = Input.GetOptional<string>("secondary_casters_raw");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, string> pair in _castersCleanup)
|
||||
{
|
||||
input = input.Replace(pair.Key, pair.Value);
|
||||
}
|
||||
|
||||
Match match = CasterRegex().Match(input);
|
||||
|
||||
if (!match.Success)
|
||||
{
|
||||
throw new($"Can't parse secondary casters: \"{input}\"");
|
||||
}
|
||||
|
||||
Object.SecondaryCasters = int.Parse(M(1));
|
||||
Object.SecondaryCastersMax = (M(2) != "") ? int.Parse(M(2)) : Object.SecondaryCasters;
|
||||
|
||||
if (M(3) != "")
|
||||
{
|
||||
Object.SecondaryCastersSuffix = new() { [LocaleType.English] = M(3) };
|
||||
}
|
||||
return;
|
||||
|
||||
string M(int i) => match.Groups[i].Value;
|
||||
}
|
||||
|
||||
private void ProcessPrimaryChecks()
|
||||
{
|
||||
string? check = Input.GetOptional<string>("primary_check_markdown");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(check))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> parts = CheckStringPrepare(check);
|
||||
|
||||
string suffix = "";
|
||||
|
||||
// Обработка частей
|
||||
List<RitualCheck> ritualChecks = parts
|
||||
.Select(part => ResolveCheck(part.Trim(), true, out suffix))
|
||||
.ToList();
|
||||
|
||||
if (
|
||||
ritualChecks.Any(c => c.Rank == TrainingRank.Untrained)
|
||||
&& ritualChecks.Any(c => c.Rank != TrainingRank.Untrained)
|
||||
)
|
||||
{
|
||||
// Смешанные ранги
|
||||
TrainingRank[] ranks = ritualChecks
|
||||
.Select(c => c.Rank)
|
||||
.Distinct()
|
||||
.Where(r => r != TrainingRank.Untrained)
|
||||
.ToArray();
|
||||
|
||||
if (ranks.Length > 1)
|
||||
{
|
||||
throw new($"Can't resolve mixed ranks: {string.Join(", ", ranks)}");
|
||||
}
|
||||
|
||||
foreach (
|
||||
RitualCheck ritualCheck in ritualChecks.Where(r => r.Rank == TrainingRank.Untrained)
|
||||
)
|
||||
{
|
||||
ritualCheck.Rank = ranks[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (suffix != "")
|
||||
{
|
||||
Object.PrimaryCheckSuffix = new() { [LocaleType.English] = suffix };
|
||||
}
|
||||
|
||||
foreach (RitualCheck ritualCheck in ritualChecks)
|
||||
{
|
||||
Object.Checks.Add(ritualCheck);
|
||||
Context.RitualChecks.Add(ritualCheck);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessSecondaryChecks()
|
||||
{
|
||||
string? check = Input.GetOptional<string>("secondary_check_markdown");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(check))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> parts = CheckStringPrepare(check);
|
||||
|
||||
foreach (string part in parts)
|
||||
{
|
||||
RitualCheck ritualCheck = ResolveCheck(part.Trim(), false, out string suffix);
|
||||
|
||||
if (suffix != "")
|
||||
{
|
||||
if (ritualCheck.TrainingString is not null)
|
||||
{
|
||||
ritualCheck.TrainingString[LocaleType.English] += $" ({suffix})";
|
||||
}
|
||||
else
|
||||
{
|
||||
ritualCheck.TrainingString = new() { [LocaleType.English] = suffix };
|
||||
}
|
||||
}
|
||||
|
||||
Object.Checks.Add(ritualCheck);
|
||||
Context.RitualChecks.Add(ritualCheck);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, string> _checksCleanupReplaces = new()
|
||||
{
|
||||
["DC 35 Arcana"] = "Arcana <DC 35>",
|
||||
[")or"] = ") or",
|
||||
["[Lore](/Skills.aspx?ID=41) (any)"] = "[Any Lore](/Skills.aspx?ID=41)",
|
||||
["[Lore](/Skills.aspx?ID=8) (any)"] = "[Any Lore](/Skills.aspx?ID=8)",
|
||||
};
|
||||
|
||||
private readonly Dictionary<Regex, string> _checksCleanupRegexes = new()
|
||||
{
|
||||
[new(@"(\w+) \[Lore\]", RegexOptions.Compiled | RegexOptions.Multiline)] = "[$1 Lore]",
|
||||
};
|
||||
|
||||
private List<string> CheckStringPrepare(string input)
|
||||
{
|
||||
// Отчистка проблемных частей
|
||||
foreach (KeyValuePair<string, string> pair in _checksCleanupReplaces)
|
||||
{
|
||||
input = input.Replace(pair.Key, pair.Value);
|
||||
}
|
||||
foreach (KeyValuePair<Regex, string> pair in _checksCleanupRegexes)
|
||||
{
|
||||
input = pair.Key.Replace(input, pair.Value);
|
||||
}
|
||||
|
||||
// Замена символа ссылок
|
||||
input = Helpers_StringHelper.LinkRegex().Replace(input, "$1[$2]{$3}");
|
||||
input = input.Replace("(", "<").Replace(")", ">").Replace("{", "(").Replace("}", ")");
|
||||
|
||||
if (input.EndsWith(';') || input.EndsWith(','))
|
||||
{
|
||||
input = input[..^1].Trim();
|
||||
}
|
||||
|
||||
// Временная замена скобок ранга и дополнения
|
||||
#pragma warning disable SYSLIB1045
|
||||
MatchCollection rankMatches = new Regex(@"<(.*?)>").Matches(input);
|
||||
#pragma warning restore SYSLIB1045
|
||||
for (int i = 0; i < rankMatches.Count; i++)
|
||||
{
|
||||
input = input.Replace(rankMatches[i].Value, $"{{rank-{i}}}");
|
||||
}
|
||||
|
||||
// Разбиваем строку на части
|
||||
List<string> parts = StringHelper.RowSplit(input);
|
||||
|
||||
// Возвращаем скобки ранга и дополнения
|
||||
for (int i = 0; i < rankMatches.Count; i++)
|
||||
{
|
||||
for (int j = 0; j < parts.Count; j++)
|
||||
{
|
||||
parts[j] = parts[j].Replace($"{{rank-{i}}}", rankMatches[i].Value);
|
||||
}
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
private RitualCheck ResolveCheck(string input, bool isPrimary, out string suffix)
|
||||
{
|
||||
RitualCheck result = new() { Ritual = Object, IsPrimary = isPrimary };
|
||||
string? skillName = null;
|
||||
string s = "";
|
||||
|
||||
Dictionary<Regex, Action<Match>> regexDictionary = new()
|
||||
{
|
||||
// General match
|
||||
// [name](url) ? <rank?> ?
|
||||
[PrimaryRegex1()] = match =>
|
||||
{
|
||||
skillName = match.Groups[1].Value;
|
||||
try
|
||||
{
|
||||
result.Rank = Input.Enum<TrainingRank>(match.Groups[4].Value.ToLower());
|
||||
s += match.Groups[3].Value + match.Groups[5].Value + match.Groups[6].Value;
|
||||
}
|
||||
catch
|
||||
{
|
||||
s +=
|
||||
match.Groups[3].Value
|
||||
+ match.Groups[4].Value
|
||||
+ match.Groups[5].Value
|
||||
+ match.Groups[6].Value;
|
||||
}
|
||||
},
|
||||
|
||||
// ? [name](url)
|
||||
[PrimaryRegex2()] = match =>
|
||||
{
|
||||
skillName = match.Groups[2].Value;
|
||||
result.Rank = TrainingRank.Untrained;
|
||||
s += match.Groups[1].Value;
|
||||
},
|
||||
|
||||
// name <rank>
|
||||
[PrimaryRegex3()] = match =>
|
||||
{
|
||||
skillName = match.Groups[1].Value;
|
||||
try
|
||||
{
|
||||
result.Rank = Input.Enum<TrainingRank>(match.Groups[2].Value.ToLower());
|
||||
}
|
||||
catch
|
||||
{
|
||||
s += match.Groups[2].Value;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
foreach (KeyValuePair<Regex, Action<Match>> pair in regexDictionary)
|
||||
{
|
||||
Match match = pair.Key.Match(input);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
pair.Value.Invoke(match);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
suffix = s;
|
||||
|
||||
skillName ??= input;
|
||||
|
||||
result.Training = Context.Trainings.FirstOrDefault(t =>
|
||||
Pf2eDbContext.LocaleSearch(t.Name, skillName)
|
||||
);
|
||||
|
||||
result.TrainingString =
|
||||
(result.Training is not null) ? null : new() { [LocaleType.English] = skillName };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string[] AddedDescriptionPaths() =>
|
||||
[
|
||||
"summary_markdown",
|
||||
"primary_check_markdown",
|
||||
"secondary_casters_raw",
|
||||
"secondary_check_markdown",
|
||||
];
|
||||
|
||||
[GeneratedRegex(
|
||||
@"^ *\[\s*(.*?)\s*\]\((.*?)\)\s*([a-z' ]*?)<(.*?)(?:[;,]?\s*(.*?))?>([a-z' ]*?)$",
|
||||
RegexOptions.Multiline
|
||||
)]
|
||||
private static partial Regex PrimaryRegex1();
|
||||
|
||||
[GeneratedRegex(@"^ *(.*?) *\[\s*(.*?)\s*\]\((.*?)\) *$", RegexOptions.Multiline)]
|
||||
private static partial Regex PrimaryRegex2();
|
||||
|
||||
[GeneratedRegex(@"^ *(.*?)\s*<(.*?)> *$", RegexOptions.Multiline)]
|
||||
private static partial Regex PrimaryRegex3();
|
||||
|
||||
[GeneratedRegex(@"^(\d+)(?:\-(\d+))?,? *\(?(.*?)\)?$", RegexOptions.Multiline)]
|
||||
private static partial Regex CasterRegex();
|
||||
}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Base.Source;
|
||||
using Pf2e.Database.Model.Base.Targets;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using Rule = Pf2e.Database.Model.Structure.Rule;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types.Rules;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:rules",
|
||||
InnerType = "rules",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Правила",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:trait", "aonprd:source", "aonprd:rules-toc"])]
|
||||
internal class RuleProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Rule;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Rule Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Rules.Add(Object);
|
||||
|
||||
/// <summary>
|
||||
/// Структура генерации содержания правил.
|
||||
/// </summary>
|
||||
public RuleTocCollection Toc { get; } = RuleTocCollection.Instance;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
// base.Process();
|
||||
AddEntity();
|
||||
AddSource();
|
||||
AddExternal();
|
||||
AddTraits();
|
||||
|
||||
RuleTocBook book = Toc[GetSourceId()];
|
||||
|
||||
string[] breadcrumbs = (Input.GetOptional<JArray>("breadcrumbs") ?? [])
|
||||
.Select(token => token.ToString())
|
||||
.ToArray();
|
||||
|
||||
string id = GetExternal().Suffix.Replace("/Rules.aspx?ID=", "rules-");
|
||||
RuleTocItem? item;
|
||||
|
||||
if (breadcrumbs.Length > 0)
|
||||
{
|
||||
RuleTocItem parent = book.Get(breadcrumbs);
|
||||
item = parent.Children.FirstOrDefault(child => child.Id == id);
|
||||
|
||||
if (item is null)
|
||||
{
|
||||
item = new(Entity.Name[LocaleType.English], parent);
|
||||
parent.Children.Add(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item = book.Children.First(child => child.Id == id);
|
||||
}
|
||||
|
||||
item.Id = Input.GetRequired<string>("id");
|
||||
item.RuleId = Object.Id;
|
||||
item.IsHandled = true;
|
||||
|
||||
if (item.Parent?.IsHandled ?? false)
|
||||
{
|
||||
Object.ParentId = item.Parent.RuleId!;
|
||||
Object.Order = item.Parent.ChildrenOrder?.IndexOf(item.Id) ?? -1;
|
||||
}
|
||||
|
||||
// ЗАМЕТКА
|
||||
//
|
||||
// Индекс Архивов не включает поля "next_link" и "previous_link"!
|
||||
|
||||
/*
|
||||
if (item.ChildrenOrder is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
item.PreviousId = Input
|
||||
.GetOptional<string>("previous_link")
|
||||
?.Replace("/Rules.aspx?ID=", "rules-");
|
||||
item.NextId = Input.GetOptional<string>("next_link")?.Replace("/Rules.aspx?ID=", "rules-");
|
||||
|
||||
if (item.Parent is not null)
|
||||
{
|
||||
if (item.PreviousId is null)
|
||||
{
|
||||
item.Parent.FirstChildId = item.Id;
|
||||
}
|
||||
if (item.NextId is null)
|
||||
{
|
||||
item.Parent.LastChildId = item.Id;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение источника, к которому относится правило.
|
||||
/// </summary>
|
||||
/// <returns>Источник, к которому относится правило.</returns>
|
||||
private int GetSourceId()
|
||||
{
|
||||
foreach (EntitySource entitySource in Entity.Sources)
|
||||
{
|
||||
return entitySource.SourceId;
|
||||
}
|
||||
|
||||
throw new("Source not found");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение внешней ссылки, из которой получено правило.
|
||||
/// </summary>
|
||||
/// <returns>Внешняя ссылка.</returns>
|
||||
private EntityExternal GetExternal()
|
||||
{
|
||||
foreach (EntityExternal entityExternal in Entity.Externals)
|
||||
{
|
||||
return entityExternal;
|
||||
}
|
||||
|
||||
throw new("External not found");
|
||||
}
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
// ЗАМЕТКА
|
||||
//
|
||||
// В теории, этот метод должен был дополнительно устанавливать порядок разделов.
|
||||
// Но индекс Архивов не включает поля "next_link" и "previous_link",
|
||||
// так что ставить порядок ВСЕХ правил в архиве не получится, только тех, что есть в содержании.
|
||||
// Ну а пока просто расставляем родительские и дочерние элементы.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Definitions;
|
||||
using Pf2e.Database;
|
||||
using Rule = Pf2e.Database.Model.Structure.Rule;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types.Rules;
|
||||
|
||||
[Processor(
|
||||
"aonprd:rules-order",
|
||||
Description = "Формирование порядка правил",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:rules"])]
|
||||
internal class RulesOrderProcessor(Pf2eDbContext context) : IProcessor
|
||||
{
|
||||
public Pf2eDbContext Context { get; } = context;
|
||||
|
||||
/// <summary>
|
||||
/// Структура генерации содержания правил.
|
||||
/// </summary>
|
||||
public readonly RuleTocCollection Toc = RuleTocCollection.Instance;
|
||||
|
||||
/// <summary>
|
||||
/// Список записей о порядке правил в своих главах.
|
||||
/// </summary>
|
||||
private readonly List<OrderItem> _orderItems = [];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Process()
|
||||
{
|
||||
Toc.SaveFile();
|
||||
|
||||
/*
|
||||
foreach (RuleTocBook book in Toc.Books)
|
||||
{
|
||||
BuildIdOrderDictionary(book.Children);
|
||||
}
|
||||
*/
|
||||
|
||||
int count = Context.Rules.Count();
|
||||
const int perPage = 50;
|
||||
|
||||
for (int skip = 0; skip < count; skip += perPage)
|
||||
{
|
||||
Context.Rules.Skip(skip).Take(perPage).ToList().ForEach(Process);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка конкретного правила.
|
||||
/// </summary>
|
||||
/// <param name="rule"></param>
|
||||
private void Process(Rule rule)
|
||||
{
|
||||
RuleTocItem? item = Toc.FindEntityId(rule.Id);
|
||||
|
||||
if (item is null)
|
||||
{
|
||||
throw new($"Rule with id {rule.Id} not found in TOC");
|
||||
}
|
||||
|
||||
rule.ParentId = item.Parent?.RuleId;
|
||||
|
||||
// Дети будут раставлены автоматически по связи
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Построение списка записей о порядке правил из дочерних элементов содержания.
|
||||
/// </summary>
|
||||
/// <param name="item">Элемент содержания, дочерние элементы которого необходимо обработать.</param>
|
||||
private void BuildIdOrderDictionary(RuleTocItem item)
|
||||
{
|
||||
List<RuleTocItem> items = [];
|
||||
|
||||
if (item.ChildrenOrder is null)
|
||||
{
|
||||
RuleTocItem? child = item.Children.FirstOrDefault(i => i.Id == item.FirstChildId);
|
||||
|
||||
while (child is not null)
|
||||
{
|
||||
items.Add(child);
|
||||
child = item.Children.FirstOrDefault(i => i.Id == child.NextId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (string id in item.ChildrenOrder)
|
||||
{
|
||||
RuleTocItem? child = item.Children.FirstOrDefault(i => i.Id == id);
|
||||
if (child is null)
|
||||
{
|
||||
throw new($"Child with id {id} not found in {item.Name}");
|
||||
}
|
||||
|
||||
items.Add(child);
|
||||
}
|
||||
}
|
||||
|
||||
if (items.Count != item.Children.Count)
|
||||
{
|
||||
throw new($"Children count mismatch for {item.Name}");
|
||||
}
|
||||
|
||||
BuildIdOrderDictionary(items);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Построение списка записей о порядке правил из списка элементов содержания.
|
||||
/// </summary>
|
||||
/// <param name="items">Список элементов содержания для обработки.</param>
|
||||
private void BuildIdOrderDictionary(List<RuleTocItem> items)
|
||||
{
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
RuleTocItem item = items[i];
|
||||
|
||||
if (item.RuleId is null)
|
||||
{
|
||||
throw new($"RuleId is null for {item.Name} (id {item.Id}");
|
||||
}
|
||||
|
||||
AddOrderItem((int)item.RuleId!, i, null);
|
||||
BuildIdOrderDictionary(item);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавление элемента содержания.
|
||||
/// </summary>
|
||||
/// <param name="id">Идентификатор правила.</param>
|
||||
/// <param name="order">Порядок правила.</param>
|
||||
/// <param name="parentId">Идентификатор главы, в которой находится глава.</param>
|
||||
private void AddOrderItem(int id, int order, int? parentId)
|
||||
{
|
||||
if (_orderItems.Any(item => item.Id == id))
|
||||
{
|
||||
throw new($"Order item with id {id} already exists");
|
||||
}
|
||||
|
||||
_orderItems.Add(
|
||||
new()
|
||||
{
|
||||
Id = id,
|
||||
Order = order,
|
||||
ParentId = parentId,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Save()
|
||||
{
|
||||
Context.SaveChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Запись, указывающая порядок правила в своей главе.
|
||||
/// </summary>
|
||||
private record OrderItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Идентификатор правила.
|
||||
/// </summary>
|
||||
public int Id { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Порядок правила.
|
||||
/// </summary>
|
||||
public int Order { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Идентификатор главы, в которой находится глава.
|
||||
/// </summary>
|
||||
public int? ParentId { get; init; }
|
||||
}
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using AngleSharp;
|
||||
using AngleSharp.Dom;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Definitions;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Base.Source;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types.Rules;
|
||||
|
||||
[Processor(
|
||||
"aonprd:rules-toc",
|
||||
Description = "Загрузка содержания правил",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:source"])]
|
||||
internal partial class RulesTocProcessor(Pf2eDbContext context) : IProcessor
|
||||
{
|
||||
public Pf2eDbContext Context { get; } = context;
|
||||
|
||||
/// <summary>
|
||||
/// Селектор HTML-элемента, в котором находится содержание.
|
||||
/// </summary>
|
||||
private const string Selector = "#ctl00_RadDrawer1_Content_MainContent_DetailedOutput";
|
||||
|
||||
/// <summary>
|
||||
/// Ссылка на страницу с содержанием.
|
||||
/// </summary>
|
||||
private const string Url = "https://2e.aonprd.com/Rules.aspx";
|
||||
|
||||
/// <summary>
|
||||
/// Структура генерации содержания правил.
|
||||
/// </summary>
|
||||
public readonly RuleTocCollection Toc = RuleTocCollection.Instance;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Process()
|
||||
{
|
||||
IDocument document = DownloadPage();
|
||||
|
||||
foreach (IElement block in document.QuerySelector(Selector)!.Children)
|
||||
{
|
||||
IElement summaryElement =
|
||||
block.QuerySelector("summary") ?? throw new("Can't determine <summary> element");
|
||||
|
||||
string sourceName = summaryElement.TextContent;
|
||||
Source source =
|
||||
Context.Sources.FirstOrDefault(s => s.Name == sourceName)
|
||||
?? throw new($"Source {sourceName} not found");
|
||||
|
||||
RuleTocBook book = Toc[source];
|
||||
|
||||
for (int i = 1; i < block.Children.Length; i++)
|
||||
{
|
||||
IElement element = block.Children[i];
|
||||
|
||||
if (element.TagName != "B")
|
||||
{
|
||||
throw new($"Expected <B> tag, but got <{element.TagName}>");
|
||||
}
|
||||
|
||||
RuleTocItem item = ParseLink(element.InnerHtml);
|
||||
item.ChildrenOrder = [];
|
||||
|
||||
book.Children.Add(item);
|
||||
|
||||
if (element.NextElementSibling?.TagName != "UL")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IElement ul = block.Children[++i];
|
||||
|
||||
foreach (IElement li in ul.Children)
|
||||
{
|
||||
RuleTocItem child = ParseLink(li.InnerHtml);
|
||||
|
||||
item.Children.Add(child);
|
||||
item.ChildrenOrder.Add(child.Id!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Toc.SaveFile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка ссылки в содержании для создания нового элемента содержания..
|
||||
/// </summary>
|
||||
/// <param name="value">Строка с ссылкой.</param>
|
||||
/// <param name="parent">Родительсий элемент, к которому будет относиться новый элемент содержания.</param>
|
||||
/// <returns>Новый элемент содержания.</returns>
|
||||
private RuleTocItem ParseLink(string value, RuleTocItem? parent = null)
|
||||
{
|
||||
Match linkMatch = LinkRegex().Match(value);
|
||||
|
||||
if (!linkMatch.Success)
|
||||
{
|
||||
throw new($"Can't parse link {value}");
|
||||
}
|
||||
|
||||
return new(HttpUtility.HtmlDecode(linkMatch.Groups[2].Value).Trim(), parent)
|
||||
{
|
||||
Id = $"rules-{linkMatch.Groups[1].Value}",
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Скачивание страницы, указанной в <see cref="Url"/>, и получение очищенного элемента, указанного в <see cref="Selector"/>.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private IDocument DownloadPage()
|
||||
{
|
||||
IConfiguration config = Configuration.Default.WithDefaultLoader();
|
||||
IBrowsingContext context = BrowsingContext.New(config);
|
||||
IDocument document = null!;
|
||||
bool completed = false;
|
||||
|
||||
while (!completed)
|
||||
{
|
||||
try
|
||||
{
|
||||
document = context.OpenAsync(Url).Result;
|
||||
completed = true;
|
||||
}
|
||||
catch (AggregateException)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
IElement root = document.QuerySelector(Selector) ?? throw new("Broken page download");
|
||||
|
||||
string html = root.OuterHtml;
|
||||
|
||||
foreach (string s in new[] { "br", "\r", "\n", "<u>", "</u>", "&NoRedirect=1" })
|
||||
{
|
||||
html = html.Replace(s, "");
|
||||
}
|
||||
|
||||
return context.OpenAsync(req => req.Content(html)).Result;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Save() { }
|
||||
|
||||
/// <summary>
|
||||
/// Получить скомпилированное регулярное выражение для получения HTML-ссылки.
|
||||
/// </summary>
|
||||
/// <returns>Регулярное выражение получения HTML-ссылки.</returns>
|
||||
[GeneratedRegex("""<a href="Rules\.aspx\?ID=(\d+)">(.*?)</a>""")]
|
||||
public static partial Regex LinkRegex();
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:skill-general-action",
|
||||
InnerType = "skill-general-action",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Действия скиллов",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:trait", "aonprd:source"])]
|
||||
internal class SkillActionsProcessor(
|
||||
ProcessorInput input,
|
||||
StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Action;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Database.Model.Structure.Action Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Actions.Add(Object);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
Check();
|
||||
|
||||
base.Process();
|
||||
|
||||
Object.Actions = ActionEnum.Other;
|
||||
Object.Category = ActionCategory.SkillAction;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string[] AddedDescriptionPaths() =>
|
||||
[
|
||||
"cost_markdown",
|
||||
"trait_markdown",
|
||||
"source_markdown",
|
||||
"search_markdown",
|
||||
"requirement_markdown",
|
||||
"trigger_markdown",
|
||||
"summary_markdown",
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Pf2e.Database.Model.Structure.SpellRelation;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:spell",
|
||||
InnerType = "spell",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Заклинания",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:trait", "aonprd:source"])]
|
||||
internal class SpellProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Spell;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Spell Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Spells.Add(Object);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
|
||||
Object.Level = Input.GetRequired<int>("level");
|
||||
Object.Actions = Input.EnumOptional("actions", ActionEnum.Unknown);
|
||||
Object.IsFocus = Input.GetRequired<string>("spell_type") == "Focus";
|
||||
Object.Duration = Input.GetOptional("duration", -1);
|
||||
Object.Range = Input.GetOptional("range", -1);
|
||||
|
||||
Object.Cost = Input.GetOptionalLocale("cost_markdown", LocaleType.English);
|
||||
Object.Trigger = Input.GetOptionalLocale("trigger_markdown", LocaleType.English);
|
||||
Object.Target = Input.GetOptionalLocale("target_markdown", LocaleType.English);
|
||||
Object.Requirement = Input.GetOptionalLocale("requirement_markdown", LocaleType.English);
|
||||
|
||||
Object.Traditions = (Input.GetOptional<JArray>("tradition") ?? [])
|
||||
.Select(token => Input.Enum<SpellTradition>(token.ToString()))
|
||||
.ToArray();
|
||||
|
||||
Object.Elements = (Input.GetOptional<JArray>("element") ?? [])
|
||||
.Select(token => Input.Enum<ElementEnum>(token.ToString()))
|
||||
.ToArray();
|
||||
|
||||
switch (Input.GetRequired<string>("spell_type"))
|
||||
{
|
||||
case "Focus":
|
||||
Object.IsFocus = true;
|
||||
break;
|
||||
case "Cantrip":
|
||||
Object.Level = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ProcessArea();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обработка области применения заклинания.
|
||||
/// </summary>
|
||||
private void ProcessArea()
|
||||
{
|
||||
List<string> areaTypes = (Input.GetOptional<string[]>("area_type") ?? []).ToList();
|
||||
|
||||
switch (areaTypes.Count)
|
||||
{
|
||||
case 0:
|
||||
return;
|
||||
|
||||
case 1:
|
||||
A(
|
||||
new()
|
||||
{
|
||||
Spell = Object,
|
||||
Type = Input.Enum<SpellAreaType>(areaTypes[0]),
|
||||
Details = Input.GetOptionalLocale("area_raw", LocaleType.English),
|
||||
}
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> areaDetails = (Input.GetOptional<string>("area_raw") ?? "")
|
||||
.Replace(", or", ",")
|
||||
.Replace(" or ", ", ")
|
||||
.Split(", ")
|
||||
.ToList();
|
||||
|
||||
if (areaTypes.Remove("square"))
|
||||
{
|
||||
A(new() { Spell = Object, Type = SpellAreaType.Square });
|
||||
}
|
||||
if (areaDetails.Contains("fungi"))
|
||||
{
|
||||
areaDetails = [areaDetails[0] + " or " + areaDetails[1]];
|
||||
}
|
||||
|
||||
if (areaTypes.Count != areaDetails.Count)
|
||||
{
|
||||
throw new(
|
||||
$"Area details count does not match area types count for spell {Entity.Name[LocaleType.English]}"
|
||||
);
|
||||
}
|
||||
|
||||
for (int i = 0; i < areaTypes.Count; i++)
|
||||
{
|
||||
A(
|
||||
new()
|
||||
{
|
||||
Spell = Object,
|
||||
Type = Input.Enum<SpellAreaType>(areaTypes[i]),
|
||||
Details = new() { [LocaleType.English] = areaDetails[i] },
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
void A(SpellArea spellArea)
|
||||
{
|
||||
Object.SpellAreas.Add(spellArea);
|
||||
Context.SpellAreas.Add(spellArea);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string[] AddedDescriptionPaths() =>
|
||||
[
|
||||
"range",
|
||||
"range_raw",
|
||||
"bloodline_markdown",
|
||||
"cost_markdown",
|
||||
"deity_markdown",
|
||||
"domain_markdown",
|
||||
"lesson_markdown",
|
||||
"mystery_markdown",
|
||||
"requirement_markdown",
|
||||
"summary_markdown",
|
||||
"tradition_markdown",
|
||||
"patron_theme_markdown",
|
||||
"saving_throw_markdown",
|
||||
];
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Scrapper.Processors.Definitions;
|
||||
using Pf2e.Scrapper.Processors.Factory;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Subclasses;
|
||||
using Pf2e.Database;
|
||||
using Pf2e.Database.Model.Base;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorFactory(
|
||||
"aonprd:trait-alignments",
|
||||
ProcessorType = typeof(TraitAlignmentsProcessor),
|
||||
Description = "Трейты мировоззрений",
|
||||
Group = ProcessorGroupEnum.AonprdPreparation,
|
||||
Parallel = false
|
||||
)]
|
||||
internal class TraitAlignmentsProcessorFactory(IServiceProvider serviceProvider)
|
||||
: AbstractProcessorFactory
|
||||
{
|
||||
public IServiceProvider ServiceProvider { get; } = serviceProvider;
|
||||
public List<string> Alignments { get; } = ["LG", "NG", "CG", "LN", "N", "CN", "LE", "NE", "CE"];
|
||||
|
||||
public override int Count()
|
||||
{
|
||||
return Alignments.Count;
|
||||
}
|
||||
|
||||
public override IEnumerable<Tuple<string, IProcessor>> GetEnumerator()
|
||||
{
|
||||
foreach (string alignment in Alignments)
|
||||
{
|
||||
TraitAlignmentsProcessor processor =
|
||||
ActivatorUtilities.CreateInstance<TraitAlignmentsProcessor>(
|
||||
ServiceProvider,
|
||||
alignment
|
||||
);
|
||||
|
||||
yield return new($"{alignment}", processor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class TraitAlignmentsProcessor(
|
||||
string alignment,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : IProcessor
|
||||
{
|
||||
public string Alignment { get; } = alignment;
|
||||
public DatabaseHelper Helper { get; } = helper;
|
||||
public AonprdBuilderGlobals Globals { get; } = globals;
|
||||
public Pf2eDbContext Context { get; } = new();
|
||||
|
||||
public Entity Entity { get; set; } = null!;
|
||||
public Trait Trait { get; set; } = null!;
|
||||
|
||||
public void Process()
|
||||
{
|
||||
Entity = new()
|
||||
{
|
||||
Name = new() { ["en"] = Alignment },
|
||||
Type = EntityType.Trait,
|
||||
Img = "",
|
||||
Description = "",
|
||||
Rarity = EntityRarity.Common,
|
||||
IsTranslated = false,
|
||||
IsChecked = false,
|
||||
Slug = Helper.GenerateSlug(Alignment),
|
||||
};
|
||||
|
||||
Trait = new() { Entity = Entity, Type = TraitType.Alignment };
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
Context.Entities.Add(Entity);
|
||||
Context.Traits.Add(Trait);
|
||||
|
||||
Globals.TraitIds[Alignment] = Entity.Id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
using Helpers_StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
using StringHelper = Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers.StringHelper;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:trait",
|
||||
InnerType = "trait",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Признаки",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(
|
||||
["aonprd:external", "aonprd:source", "aonprd:source", "aonprd:trait-alignments"]
|
||||
)]
|
||||
internal class TraitProcessor(
|
||||
ProcessorInput input,
|
||||
Helpers_StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Trait;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Trait Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add()
|
||||
{
|
||||
Context.Traits.Add(Object);
|
||||
|
||||
Globals.TraitIds[Entity.Name[LocaleType.English]] = Entity.Id;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
|
||||
Object.Type = TraitType.Regular;
|
||||
|
||||
Context.Traits.Add(Object);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void AddTraits()
|
||||
{
|
||||
// Необходимо пропускать
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override string GetDescription() =>
|
||||
base.GetDescription() + AddedDescription(["summary_markdown", "search_markdown"]);
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Pf2e.Scrapper.Helpers;
|
||||
using Pf2e.Scrapper.Importers.Implementations.Aonprd.Helpers;
|
||||
using Pf2e.Scrapper.Processors;
|
||||
using Pf2e.Scrapper.Processors.Attributes;
|
||||
using Pf2e.Database.Model.Enum;
|
||||
using Pf2e.Database.Model.Structure;
|
||||
|
||||
namespace Pf2e.Scrapper.Importers.Implementations.Aonprd.Processors.Types;
|
||||
|
||||
[ProcessorCollection(
|
||||
"aonprd:versitile-heritage",
|
||||
InnerType = "ancestry",
|
||||
CompendiumType = ProcessorCompendiumEnum.Aonprd,
|
||||
Description = "Универсальные наследства",
|
||||
Group = ProcessorGroupEnum.AonprdEntities
|
||||
)]
|
||||
[ProcessorDependencies(["aonprd:ancestry"])]
|
||||
internal class VersitileHeritageProcessor(
|
||||
ProcessorInput input,
|
||||
StringHelper stringHelper,
|
||||
DatabaseHelper helper,
|
||||
AonprdBuilderGlobals globals
|
||||
) : AbstractEntityProcessor(input, stringHelper, helper, globals)
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override EntityType Type => EntityType.Heritage;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Heritage Object { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Add() => Context.Heritages.Add(Object);
|
||||
|
||||
public override void Check()
|
||||
{
|
||||
base.Check();
|
||||
|
||||
if (Input.GetRequired<string>("type") == "Ancestry")
|
||||
{
|
||||
throw new SkipItemException(
|
||||
Input.GetRequired<string>("name"),
|
||||
"не универсальное наследие"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Process()
|
||||
{
|
||||
base.Process();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user