Продолжение работы

This commit is contained in:
2025-05-13 19:22:41 +04:00
parent aad2081912
commit 83ee914991
64 changed files with 1252 additions and 1229 deletions
@@ -0,0 +1,17 @@
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
/// <summary>
/// Тип документов компендиума.
/// </summary>
internal enum CompendiumDocumentType
{
Actor,
Adventure,
Cards,
Item,
JournalEntry,
Macro,
Playlist,
RollTable,
Scene,
}
@@ -0,0 +1,87 @@
using Newtonsoft.Json.Linq;
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
/// <summary>
/// Папка компендиума.
/// </summary>
internal class CompendiumFolder
{
/// <summary>
/// Идентификатор папки.
/// </summary>
public string Id { get; }
/// <summary>
/// Название папки.
/// </summary>
public string Name { get; }
/// <summary>
/// Путь к папке.
/// </summary>
public string? Path { get; }
/// <summary>
/// Указатель, что папка содержится в других папках.
/// </summary>
public bool IsContained { get; }
/// <summary>
/// Тип документов в папке.
/// </summary>
public CompendiumDocumentType Type { get; }
/// <summary>
/// Родительская папка.
/// </summary>
public CompendiumFolder? Parent { get; set; } = null;
/// <summary>
/// Конструктор папки компендиума из JSON-объекта.
/// </summary>
/// <param name="json"></param>
public CompendiumFolder(JObject json)
{
if (json.TryGetValue("_id", out JToken? id))
{
// Вложенная папка через _folders.json
Id = id.ToString();
Name = json["name"]!.ToString();
Path = null;
IsContained = true;
}
else
{
// Корневой пак в system.json
Id = json["name"]!.ToString();
Name = json["label"]!.ToString();
Path = json["path"]!.ToString();
IsContained = false;
}
Type = Enum.Parse<CompendiumDocumentType>(json["type"]!.ToString());
}
/// <summary>
/// Конструктор папки компендиума.
/// </summary>
/// <param name="id">Идентификатор папки.</param>
/// <param name="name">Название папки.</param>
public CompendiumFolder(string id, string name)
{
Id = id;
Name = name;
Path = null;
IsContained = false;
}
/// <summary>
/// Строковое представление данных о папки компендиума.
/// </summary>
/// <returns>Строковое представление данных о папки компендиума.</returns>
public override string ToString()
{
return $"CompendiumFolder([Id={Id}][Type={Type}][Group={Name}][Path={Path}][Parent={Parent?.Name ?? "null"}])";
}
}
@@ -0,0 +1,31 @@
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
/// <summary>
/// Коллекция папок компендиума
/// </summary>
internal class CompendiumFolderCollection
{
/// <summary>
/// Список загруженных папок.
/// </summary>
public List<CompendiumFolder> Items { get; } = [];
/// <summary>
/// Добавление информации о папке.
/// </summary>
/// <param name="folder">Добавляемая папка.</param>
public void Add(CompendiumFolder folder)
{
Items.Add(folder);
}
/// <summary>
/// Получение папки по идентификатору
/// </summary>
/// <param name="id">Искомый идентификатор</param>
/// <returns>Искомая папка</returns>
public CompendiumFolder? GetById(string id)
{
return Items.FirstOrDefault(x => x.Id == id);
}
}
@@ -0,0 +1,25 @@
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
/// <summary>
/// Ссылка на сущность с указанием файла, в котором она хранится.
/// </summary>
/// <param name="id">Идентификатор сущности.</param>
/// <param name="type">Тип сущности.</param>
/// <param name="file">Имя файла, в котором хранится сущность.</param>
internal class FoundryEnCompendiumItem(string id, string type, string file) : AbstractCompendiumItem
{
/// <summary>
/// Идентификатор сущности.
/// </summary>
public override string Id { get; } = id;
/// <summary>
/// Тип сущности.
/// </summary>
public override string Type { get; } = type;
/// <summary>
/// Имя файла, в котором хранится сущность.
/// </summary>
public string File { get; } = file;
}
@@ -0,0 +1,180 @@
using System.Security.Cryptography;
using System.Text;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json.Linq;
using Pf2eDataScrapper.Helpers;
using Pf2eDataScrapper.Processors;
using Pf2eModel;
using Pf2eModel.Model;
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Base.Source;
using Pf2eModel.Model.Base.Targets;
using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure;
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.DataBuilder;
internal abstract class FoundryEnAbstractProcessor(
DatabaseHelper databaseHelper,
Pf2eDbContext context,
ProcessorInput input
) : AbstractInputProcessor(input)
{
protected DatabaseHelper Helper { get; } = databaseHelper;
public Pf2eDbContext Context { get; } = context;
public Entity Entity { get; set; } = new();
public abstract EntityType Type { get; }
public abstract IEntity Object { get; }
public override void Process()
{
Entity.Id = Helper.NextEntityId;
Entity.Type = Type;
Entity.Name[LocaleType.English] = Input.GetRequired<string>("name");
Entity.Img = Input.GetRequired<string>("img");
Entity.Description = Input.GetRequired<string>("system.description.value");
Entity.IsTranslated = false;
Entity.IsChecked = false;
Entity.Slug = Helper.GenerateSlug(Entity.Name[LocaleType.English]);
Entity.Rarity = Input.EnumOptional("system.traits.rarity", EntityRarity.Common);
Object.Id = Entity.Id;
Context.Entities.Add(Entity);
// Alias
/*
EntityAlias alias = new()
{
Type = LocaleType.English,
Alias = Entity.Group,
EntityId = Entity.Id,
Entity = Entity
};
Context.EntityAliases.Add(alias);
*/
// Source
EntitySource source = new()
{
Entity = Entity,
Source = GetSource(Input.GetRequired<string>("system.publication.title")),
Suffix = "",
IsRemaster = Input.GetRequired<bool>("system.publication.remaster"),
};
Context.EntitySources.Add(source);
// External
EntityExternal external = new()
{
Entity = Entity,
Target = GetTarget(),
Suffix = Input.GetRequired<string>("_id"),
Md5 = Md5(Input.Input.ToString()),
};
Context.EntityExternals.Add(external);
// Traits
JToken? traitsJson = Input.Input.SelectToken("system.traits.value");
if (traitsJson?.Type != JTokenType.Array)
{
throw new Exception("system.traits.value is expected to be an array");
}
foreach (Trait trait in GetTraits(traitsJson.ToArray().Select(jToken => jToken.ToString())))
{
Entity.Traits.Add(trait);
}
}
public override void Save()
{
Context.SaveChanges();
}
protected Source GetSource(string name)
{
Source? source = Context.Sources.FirstOrDefault(s => s.Name == name);
if (source != null)
{
return source;
}
source = new() { Name = name };
Context.Sources.Add(source);
return source;
}
protected ExternalTarget GetTarget()
{
const string name = "pf2e - Foundry module";
ExternalTarget? target = Context.ExternalTargets.FirstOrDefault(s => s.Name == name);
if (target != null)
{
return target;
}
target = new()
{
Name = "pf2e - Foundry module",
Icon = "",
Prefix = "https://github.com/foundryvtt/pf2e",
};
Context.ExternalTargets.Add(target);
return target;
}
protected IEnumerable<Trait> GetTraits(IEnumerable<string> names)
{
List<Trait> result = Context
.Traits.Include(t => t.Entity)
.ThenInclude(e => e.Name)
// ReSharper disable once EntityFramework.UnsupportedServerSideFunctionCall
.Where(t => Pf2eDbContext.LocaleSearchArray(t.Entity.Name, names))
.ToList();
/*
foreach (string name in names)
{
if (result.Any(t => t.Entity.Group.Contains(name)))
{
continue;
}
Trait trait = new()
{
Group = name,
Slug = name,
Type = TraitType.Regular,
Description = "",
};
Context.Traits.Add(trait);
result.Add(trait);
}
*/
return result;
}
public static string Md5(string input, bool isLowercase = false)
{
using MD5 md5 = MD5.Create();
byte[] byteHash = md5.ComputeHash(Encoding.UTF8.GetBytes(input));
string hash = BitConverter.ToString(byteHash).Replace("-", "");
return isLowercase ? hash.ToLower() : hash;
}
}
@@ -0,0 +1,43 @@
using Newtonsoft.Json.Linq;
using Pf2eDataScrapper.App;
using Pf2eDataScrapper.Helpers;
using Pf2eDataScrapper.Importers.Implementations.FoundryEn.DataBuilder;
using Pf2eDataScrapper.Processors;
using Pf2eModel;
using Pf2eModel.Model.Enum;
namespace Pf2eDataScrapper.Importers.Implementations.Pf2eFoundry.DataBuilder.Processors;
[Processor(
"foundry-en:action",
InnerType = "action",
Description = "Создание цели внешних ссылок",
Group = ProcessorGroupEnum.FoundryEnEntities
)]
[ProcessorDependencies(["foundry-en:compendium"])]
internal class ActionProcessor(
DatabaseHelper databaseHelper,
Pf2eDbContext context,
ProcessorInput input
) : FoundryEnAbstractProcessor(databaseHelper, context, input)
{
public override EntityType Type => EntityType.Action;
public override Pf2eModel.Model.Structure.Action Object { get; } = new();
public override void Process()
{
base.Process();
/*
Object.Type = EnumRequired<ActionType>("system.actionType.value");
Object.Category = EnumOptional<ActionCategory>("system.category", ActionCategory.Unknown);
Object.Actions = GetOptional<int>("system.actions.value");
Object.DeathNote = GetOptional<bool>("system.deathNote");
*/
JObject extra = new() { { "selfEffect", Input.Input.SelectToken("system.selfEffect") } };
Object.Extra = extra.ToString(Newtonsoft.Json.Formatting.None);
Context.Actions.Add(Object);
}
}
@@ -0,0 +1,46 @@
using Newtonsoft.Json.Linq;
using Pf2eDataScrapper.App;
using Pf2eDataScrapper.Helpers;
using Pf2eDataScrapper.Importers.Implementations.FoundryEn.DataBuilder;
using Pf2eDataScrapper.Processors;
using Pf2eModel;
using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure;
namespace Pf2eDataScrapper.Importers.Implementations.Pf2eFoundry.DataBuilder.Processors;
[Processor(
"foundry-en:condition",
InnerType = "Item.condition",
Description = "Создание цели внешних ссылок",
Group = ProcessorGroupEnum.FoundryEnEntities
)]
[ProcessorDependencies(["foundry-en:compendium"])]
internal class ConditionProcessor(
DatabaseHelper databaseHelper,
Pf2eDbContext context,
ProcessorInput input
) : FoundryEnAbstractProcessor(databaseHelper, context, input)
{
public override EntityType Type => EntityType.Condition;
public override Condition Object { get; } = new();
public override void Process()
{
base.Process();
JObject extra = new()
{
{ "duration", Input.Input.SelectToken("system.duration") },
{ "overrides", Input.Input.SelectToken("system.overrides") },
{ "references", Input.Input.SelectToken("system.references") },
{ "value", Input.Input.SelectToken("system.value") },
};
Object.Extra = extra.ToString(Newtonsoft.Json.Formatting.None);
Object.Group = Input.EnumOptional("system.group", ConditionGroup.Unknown);
Context.Conditions.Add(Object);
}
}
@@ -0,0 +1,63 @@
using Newtonsoft.Json.Linq;
using Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn;
/// <summary>
/// Загрузчик данных компендиума.
/// </summary>
/// <param name="repository">Репозиторий данных.</param>
internal sealed class FoundryEnCompendium(
FoundryEnRepository repository,
CompendiumFolderCollection folders
) : AbstractCompendium
{
/// <summary>
/// Репозиторий данных.
/// </summary>
public override FoundryEnRepository Repository { get; } = repository;
/// <summary>
/// Набор папок компендиума
/// </summary>
public CompendiumFolderCollection Folders { get; } = folders;
/// <summary>
/// Коллекция всех записей компендиума.
/// </summary>
public List<FoundryEnCompendiumItem> Items { get; } = [];
/// <summary>
/// Возвращает количество элементов в компендиуме.
/// </summary>
/// <returns>Количество элементов.</returns>
public override int Count() => Items.Count;
/// <summary>
/// Возвращает количество элементов для указанного типа данных.
/// </summary>
/// <param name="type">Тип данных.</param>
/// <returns>Количество элементов.</returns>
public override int Count(string type) => Items.Count(i => i.Type == type);
/// <summary>
/// Получение итератора сущностей. Если указан тип <paramref name="type"/> - то только указанного типа.
/// </summary>
/// <param name="type">Тип сущностей, которые нужно получить.</param>
/// <returns>Итератор сущностей.</returns>
public override IEnumerable<Tuple<AbstractCompendiumItem, JObject>> Iterate(string? type = null)
{
IEnumerable<FoundryEnCompendiumItem> items = type is null
? Items
: Items.Where(i => i.Type == type);
foreach (FoundryEnCompendiumItem item in items)
{
using StreamReader fileReader = new(
Path.Combine(Repository.RepositoryDirPath, item.File)
);
yield return new(item, JObject.Parse(fileReader.ReadToEnd()));
}
}
}
@@ -0,0 +1,57 @@
using Microsoft.Extensions.DependencyInjection;
using Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
using Pf2eDataScrapper.Importers.Implementations.FoundryEn.DataBuilder;
using Pf2eDataScrapper.Importers.Repositories;
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn;
/// <summary>
/// Импортёр для модуля Pf2e FoundryVTT.
/// </summary>
internal class FoundryEnImporter(FoundryEnRepository repository, FoundryEnCompendium compendium)
: AbstractImporter
{
/// <summary>
/// Название внешней ссылки.
/// </summary>
public const string TargetName = "Pf2e FoundryVTT module";
/// <summary>
/// Отображаемое имя импортёра.
/// </summary>
public override string Name => TargetName;
/// <summary>
/// Короткое имя импортёра.
/// </summary>
public override string Slug => "foundry-en";
public override FoundryEnRepository Repository { get; } = repository;
/// <summary>
/// Загрузчик данных компендиума.
/// </summary>
public override FoundryEnCompendium Compendium { get; } = compendium;
#region "Внедрение зависимостей"
public static void RegisterServices(IServiceCollection services)
{
services.AddSingleton<FoundryEnImporter>();
services.AddSingleton<FoundryEnRepository>();
services.AddSingleton<FoundryEnCompendium>();
services.AddSingleton<CompendiumFolderCollection>();
}
#endregion
}
/// <summary>
/// Git-репозиторий данных FoundryVTT-модуля "pf2e".
/// </summary>
/// <param name="importer"><inheritdoc cref="FoundryEnImporter"/></param>
internal class FoundryEnRepository(FoundryEnImporter importer) : GitRepository(importer, GitUrl)
{
public const string GitUrl = "https://github.com/foundryvtt/pf2e.git";
}
@@ -0,0 +1,123 @@
using Newtonsoft.Json.Linq;
using Pf2eDataScrapper.App;
using Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
using Pf2eDataScrapper.Processors;
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.Processors.Preparation;
[Processor(
"foundry-en:compendium-folders",
Description = "Загрузка каталогов компендиума",
Group = ProcessorGroupEnum.FoundryEnPreparation
)]
[ProcessorDependencies(["foundry-en:repository"])]
internal class CompendiumFolderProcessor(
FoundryEnRepository repository,
CompendiumFolderCollection folders
) : IProcessor
{
private FoundryEnRepository Repository { get; } = repository;
private CompendiumFolderCollection Folders { get; } = folders;
private string Dir => Repository.RepositoryDirPath;
private int NextFolderId { get; set; } = 0;
public void Process()
{
LoadPacks();
ScanFolders();
}
/// <summary>
/// Загрузка основных папок.
/// </summary>
private void LoadPacks()
{
using StreamReader systemFile = new(Path.Combine(Dir, "static", "system.json"));
JObject systemData = JObject.Parse(systemFile.ReadToEnd());
foreach (JToken pack in systemData["packs"]!)
{
CompendiumFolder folder = new((JObject)pack);
Folders.Add(folder);
}
if (systemData.TryGetValue("packFolders", out JToken? packFolders))
{
ProcessPackFolders((JArray)packFolders, null);
}
}
/// <summary>
/// Обработка папок компендиума в поле `packFolders`.
/// </summary>
/// <param name="folders"></param>
/// <param name="parent"></param>
private void ProcessPackFolders(JArray folders, CompendiumFolder? parent)
{
foreach (JToken token in folders)
{
JObject obj = (JObject)token;
string id = $"folder-{NextFolderId++}";
string name = obj["name"]!.ToString();
CompendiumFolder folder = new(id, name) { Parent = parent };
Folders.Add(folder);
if (obj.TryGetValue("packs", out JToken? packs))
{
foreach (JToken jToken in packs)
{
string packId = jToken.ToString();
CompendiumFolder? child = Folders.GetById(packId);
if (child is not null)
{
child.Parent = folder;
}
}
}
if (obj.TryGetValue("folders", out JToken? innerFolders))
{
ProcessPackFolders((JArray)innerFolders, folder);
}
}
}
private void ScanFolders()
{
// Поиск _folders.json
foreach (CompendiumFolder parent in Folders.Items)
{
if (parent.Path is null)
{
continue;
}
string dirPath = Path.Combine(Dir, parent.Path);
foreach (
string foldersFilePath in Directory.GetFiles(
dirPath,
"_folders.json",
SearchOption.AllDirectories
)
)
{
using StreamReader file = new(foldersFilePath);
JArray data = JArray.Parse(file.ReadToEnd());
foreach (JToken pack in data)
{
CompendiumFolder folder = new((JObject)pack) { Parent = parent };
Folders.Add(folder);
}
}
}
}
public void Save() { }
}
@@ -0,0 +1,104 @@
using Newtonsoft.Json.Linq;
using Pf2eDataScrapper.App;
using Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
using Pf2eDataScrapper.Processors;
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.Processors.Preparation;
[Processor(
"foundry-en:compendium",
Description = "Загрузка компендиума",
Group = ProcessorGroupEnum.FoundryEnPreparation
)]
[ProcessorDependencies(["foundry-en:compendium-folders"])]
internal class CompendiumItemsProcessor(
FoundryEnRepository repository,
FoundryEnCompendium compendium,
ProcessProgress progress
) : IProcessor
{
private FoundryEnRepository Repository { get; } = repository;
private FoundryEnCompendium Compendium { get; } = compendium;
public ProcessProgress Progress { get; } = progress;
private string Dir => Repository.RepositoryDirPath;
private List<CompendiumFolder> RootFolders { get; } =
compendium.Folders.Items.FindAll(f => f.Path != null);
public void Process()
{
Progress.Local.Reset(CountItems());
foreach (CompendiumFolder folder in RootFolders)
{
string dirPath = Path.Combine(Dir, folder.Path!);
foreach (
string filePath in Directory.GetFiles(
dirPath,
"*.json",
SearchOption.AllDirectories
)
)
{
string relativePath = Path.GetRelativePath(filePath, Dir);
Progress.Local.Start(relativePath);
FoundryEnCompendiumItem? item = ProcessFile(relativePath, folder);
if (item is not null)
{
Compendium.Items.Add(item);
}
Progress.Local.End();
}
}
Progress.Local.Complete();
}
private FoundryEnCompendiumItem? ProcessFile(string relativePath, CompendiumFolder folder)
{
FileInfo file = new(Path.Combine(Dir, relativePath));
if (file.Name == "_folders.json")
{
return null;
}
using StreamReader reader = new(file.FullName);
JObject itemJson = JObject.Parse(reader.ReadToEnd());
CompendiumFolder? itemFolder = folder;
JToken? itemJsonFolder = itemJson.SelectToken("folder");
if (itemJsonFolder is not null)
{
itemFolder = Compendium.Folders.GetById(itemJsonFolder.ToString());
}
if (itemFolder is null)
{
throw new(
$"Не удаётся определить папку, к которой относится элемент {file.Name} (путь: {file.FullName})"
);
}
string? type = itemJson.SelectToken("type")?.ToString();
return new(file.Name, itemFolder.Type + (type is not null ? $".{type}" : ""), relativePath);
}
private int CountItems()
{
return RootFolders.Sum(folder =>
{
string dirPath = Path.Combine(Dir, folder.Path!);
return Directory.GetFiles(dirPath, "*.json", SearchOption.AllDirectories).Length
- Directory.GetFiles(dirPath, "_folders.json", SearchOption.AllDirectories).Length;
});
}
public void Save() { }
}
@@ -0,0 +1,23 @@
using Pf2eDataScrapper.App;
using Pf2eDataScrapper.Processors;
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.Processors.Preparation;
[Processor(
"foundry-en:repository",
Description = "Обновление репозитория",
Group = ProcessorGroupEnum.FoundryEnPreparation
)]
internal class RepositoryUpdateProcessor(FoundryEnRepository repository, ProcessProgress progress)
: IProcessor
{
public FoundryEnRepository Repository { get; } = repository;
public ProcessProgress Progress { get; } = progress;
public void Process()
{
Repository.Update(Progress);
}
public void Save() { }
}
@@ -0,0 +1,99 @@
using Pf2eDataScrapper.App;
using Pf2eDataScrapper.Importers.Implementations.FoundryEn.Compendium;
using Pf2eDataScrapper.Processors;
using Pf2eDataScrapper.SchemaBuilder;
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.Processors.Preparation;
[Processor(
"foundry-en:schema",
Description = "Построение схемы данных",
Group = ProcessorGroupEnum.AonprdPreparation
)]
[ProcessorDependencies(["foundry-en:compendium"])]
internal class SchemaBuildProcessor(
FoundryEnImporter importer,
FoundryEnRepository repository,
FoundryEnCompendium compendium,
ProcessProgress progress,
ApplicationSettings settings
) : AbstractSchemaBuildProcessor
{
/// <inheritdoc cref="FoundryEnImporter"/>
protected FoundryEnImporter Importer { get; } = importer;
/// <inheritdoc cref="FoundryEnRepository"/>
protected FoundryEnRepository Repository { get; } = repository;
/// <inheritdoc cref="FoundryEnCompendium"/>
protected override FoundryEnCompendium 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);
/// <summary>
/// Определитель типов данных.
/// </summary>
protected override SchemaTypeResolver Resolver { get; } = new();
/// <summary>
/// Список типов, являющихся экипировкой.
/// </summary>
private readonly string[] _equipmentTypes =
[
"Item.equipment",
"Item.armor",
"Item.backpack",
"Item.consumable",
"Item.kit",
"Item.shield",
"Item.treasure",
"Item.weapon",
];
/// <summary>
/// Выбор целевых элементом схемы данных для типа элемента.
/// </summary>
/// <param name="type">Тип входного элемента.</param>
/// <returns>Список целевых элементов схемы данных.</returns>
private List<SchemaNode> GetSchemaNodes(string type)
{
List<SchemaNode> nodes = [];
// Общая нода
if (!Schemas.TryGetValue(type, out SchemaNode? typeNode))
{
typeNode = new() { Resolver = Resolver, Path = type };
Schemas[type] = typeNode;
}
nodes.Add(typeNode);
// Нода подкласса
if (_equipmentTypes.Contains(type))
{
nodes.Add(Schemas["Equipment"]);
}
return nodes;
}
protected override ICollection<string> GetSchemaNodes(AbstractCompendiumItem item)
{
List<string> nodes = [item.Type];
// Нода подкласса
if (_equipmentTypes.Contains(item.Type))
{
nodes.Add("Equipment");
}
return nodes;
}
}
@@ -0,0 +1,54 @@
using Newtonsoft.Json.Linq;
using Pf2eDataScrapper.SchemaBuilder;
using Pf2eDataScrapper.SchemaBuilder.Types;
namespace Pf2eDataScrapper.Importers.Implementations.FoundryEn.Processors.Preparation;
internal class SchemaTypeResolver : TypeResolver
{
public class FoundryRulesSchemaType(SchemaNode parent) : IgnoreSchemaType(parent)
{
public override string GetTypeName()
{
return "ignored (Foundry rules object)";
}
}
protected readonly List<string> DictionaryPaths =
[
"Actor.character.items.[].system.items",
"Actor.character.items.[].system.overlays",
"Item.ancestry.system.items",
"Item.ancestry.system.boosts",
"Item.background.system.boosts",
"Item.background.system.items",
"Item.class.system.items",
"Item.consumable.system.spell.system.damage",
"Item.consumable.system.spell.system.overlays",
"Item.deity.system.spells",
"Item.feat.system.subfeatures.proficiencies",
"Item.kit.system.items",
"Item.kit.system.items.[value].items",
"Item.spell.system.damage",
"Item.spell.system.heightening.damage",
"Item.spell.system.heightening.levels",
"Item.spell.system.heightening.levels.[value].damage",
"Item.spell.system.overlays",
"Item.spell.system.overlays.[value].system.damage",
"Item.spell.system.overlays.[value].system.heightening",
"Item.spell.system.overlays.[value].system.heightening.[value]",
];
/// <summary>
/// Частное определение типа поля.
/// </summary>
/// <param name="node">Поле схемы данных, для которого создаётся тип.</param>
/// <param name="value">Добавляемое значение.</param>
/// <returns>Новый тип для схемы данных. `null`, что бы использовать значение по умолчанию</returns>
protected override AbstractSchemaType? CustomResolve(SchemaNode node, JToken? value)
{
return CheckPath(node, DictionaryPaths) ? new DictionarySchemaType(node)
: node.Path.EndsWith(".rules") ? new FoundryRulesSchemaType(node)
: (AbstractSchemaType?)null;
}
}