From beb61b74499038640ed76f87ba01114d7be53e0d Mon Sep 17 00:00:00 2001 From: Ilya Kozhemyakin Date: Mon, 21 Apr 2025 08:36:46 +0400 Subject: [PATCH] =?UTF-8?q?=D0=91=D0=BE=D0=BB=D1=8C=D1=88=D0=B0=D1=8F=20?= =?UTF-8?q?=D0=BF=D0=B0=D1=87=D0=BA=D0=B0=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Aonprd/DataBuilder/AbstractProcessor.cs | 26 ++- .../Aonprd/DataBuilder/AonprdDataBuilder.cs | 6 +- .../Aonprd/DataBuilder/AonprdEnumResolver.cs | 17 +- .../DataBuilder/AonprdProcessorAttribute.cs | 4 +- .../DataBuilder/AonprdProcessorCollection.cs | 2 +- .../DataBuilder/AonprdProcessorInput.cs | 76 +++++++ .../DataBuilder/Processors/ActionProcessor.cs | 68 ++---- .../Processors/AncestryProcessor.cs | 19 +- .../Processors/BackgroundProcessor.cs | 50 +++++ .../DataBuilder/Processors/ClassProcessor.cs | 195 ++++++++++++++++++ .../DataBuilder/Processors/FeatProcessor.cs | 61 ++++++ .../Processors/LanguageProcessor.cs | 12 +- .../DataBuilder/Processors/SourceProcessor.cs | 35 ++++ .../Processors/TrainingProcessor.cs | 34 +++ .../DataBuilder/Processors/TraitProcessor.cs | 4 +- ...signer.cs => 20250420145024_1.Designer.cs} | 154 ++++++++++---- ...0250418174520_1.cs => 20250420145024_1.cs} | 171 ++++++++++----- .../Migrations/Pf2eDbContextModelSnapshot.cs | 152 ++++++++++---- Pf2eModel/Model/Common/Training.cs | 8 +- Pf2eModel/Model/Enum/ActionType.cs | 24 --- Pf2eModel/Model/Enum/EntityType.cs | 3 + Pf2eModel/Model/Enum/SpellTradition.cs | 24 +++ Pf2eModel/Model/Enum/TrainingType.cs | 23 +++ Pf2eModel/Model/Structure/Action.cs | 3 - .../AncestryRelation/AncestryBoost.cs | 4 +- Pf2eModel/Model/Structure/Archetype.cs | 32 +++ .../BackgroundRelation/BackgroundBoost.cs | 6 +- .../BackgroundRelation/BackgroundItem.cs | 2 + .../BackgroundRelation/BackgroundTraining.cs | 4 +- Pf2eModel/Model/Structure/Class.cs | 4 +- .../ClassRelation/ClassKeyAbility.cs | 4 +- .../ClassRelation/ClassProgression.cs | 4 +- .../Structure/ClassRelation/ClassTraining.cs | 7 +- Pf2eModel/Model/Structure/Feat.cs | 23 ++- Pf2eModel/Pf2eDbContext.cs | 1 - Pf2eModel/Pf2eDbContextModel.cs | 15 +- Pf2eViewer/EntityConverter.cs | 5 + Pf2eViewer/MainViewForm.cs | 79 +++++-- README.md | 8 +- 39 files changed, 1068 insertions(+), 301 deletions(-) create mode 100644 Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/BackgroundProcessor.cs create mode 100644 Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/ClassProcessor.cs create mode 100644 Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/FeatProcessor.cs create mode 100644 Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/SourceProcessor.cs create mode 100644 Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/TrainingProcessor.cs rename Pf2eModel/Migrations/{20250418174520_1.Designer.cs => 20250420145024_1.Designer.cs} (95%) rename Pf2eModel/Migrations/{20250418174520_1.cs => 20250420145024_1.cs} (94%) delete mode 100644 Pf2eModel/Model/Enum/ActionType.cs create mode 100644 Pf2eModel/Model/Enum/SpellTradition.cs create mode 100644 Pf2eModel/Model/Enum/TrainingType.cs create mode 100644 Pf2eModel/Model/Structure/Archetype.cs diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AbstractProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AbstractProcessor.cs index 6eaba7d..ebf95a2 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AbstractProcessor.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AbstractProcessor.cs @@ -1,4 +1,6 @@ -using Microsoft.EntityFrameworkCore; +using LinqToDB.Reflection; +using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Pf2eModel; using Pf2eModel.Model; @@ -13,13 +15,13 @@ using System.Text.RegularExpressions; namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder; -internal abstract partial class AbstractProcessor(ProcessorInput input) +internal abstract partial class AbstractProcessor(AonprdProcessorInput input) { protected DatabaseHelper Helper = DatabaseHelper.Instance; public readonly Pf2eDbContext Context = DatabaseHelper.DbContext; - public readonly ProcessorInput Input = input; + public readonly AonprdProcessorInput Input = input; public Entity Entity { get; set; } = new(); @@ -27,6 +29,8 @@ internal abstract partial class AbstractProcessor(ProcessorInput input) public abstract IEntity Object { get; } + protected abstract void Add(); + public virtual void Process() { if (Input.GetOptional("remaster_id") is not null) @@ -47,6 +51,7 @@ internal abstract partial class AbstractProcessor(ProcessorInput input) public void Save() { + Add(); Context.SaveChanges(); } @@ -68,6 +73,7 @@ internal abstract partial class AbstractProcessor(ProcessorInput input) Entity.IsTranslated = false; Entity.IsChecked = false; + Object.Entity = Entity; Object.Id = Entity.Id; Context.Entities.Add(Entity); @@ -229,6 +235,18 @@ internal abstract partial class AbstractProcessor(ProcessorInput input) } } + public string GenerateExtra(params string[] args) + { + Dictionary data = []; + + foreach (string key in args) + { + data.Add(key, Input.Input.SelectToken(key)); + } + + return JsonConvert.SerializeObject(data, new JsonSerializerSettings() { }); + } + public static string Md5(string input, bool isLowercase = false) { using MD5 md5 = MD5.Create(); @@ -247,4 +265,6 @@ internal abstract partial class AbstractProcessor(ProcessorInput input) private static partial Regex SourceSuffixRegex(); public class LegacyItemException(string name) : Exception($"Item '{name}' is linked with newer version, skipping.") { } + + public class SkipItemException(string name, string reason) : Exception($"Item '{name}' is skipped, reason: {reason}.") { } } diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdDataBuilder.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdDataBuilder.cs index 107b256..e8f7d41 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdDataBuilder.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdDataBuilder.cs @@ -39,7 +39,7 @@ internal class AonprdDataBuilder(AonprdLoader loader) Window output = new(0, 4, Console.WindowWidth, Console.WindowHeight - 4, window); - ProgressBar bar1 = new(bars, Loader.ItemCount, 15); + ProgressBar bar1 = new(bars, Processors.Items.Count, 15); ProgressBar bar2 = new(bars, 1, 15); int i = 0; @@ -66,6 +66,10 @@ internal class AonprdDataBuilder(AonprdLoader loader) { output.WriteLine(ex.Message); } + catch (SkipItemException ex) + { + output.WriteLine(ex.Message); + } } bar2.Refresh(j, "Processor completed"); diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdEnumResolver.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdEnumResolver.cs index 25c36a4..25422bc 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdEnumResolver.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdEnumResolver.cs @@ -4,19 +4,6 @@ namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder; public static class AonprdEnumResolver { private static readonly ICollection Solvers = [ - new Solver(new() - { - { "Single Action", ActionType.SingleAction }, - { "Reaction or One Action", ActionType.SingleAction }, - { "Free Action or One Action", ActionType.SingleAction }, - { "Two Actions", ActionType.TwoActions }, - { "Three Actions", ActionType.ThreeActions }, - { "Single Action to Three Actions", ActionType.SingleToThreeActions }, - { "Single Action or more Actions", ActionType.SingleToThreeActions }, - { "Single Action or Two Actions", ActionType.SingleToTwoActions }, - { "Single Action to Two Actions", ActionType.SingleToTwoActions }, - }), - new Solver(new() { { "Rulebooks", SourceCategory.Rulebooks }, @@ -36,7 +23,9 @@ public static class AonprdEnumResolver new Solver(new() { - { "Consitution", AttributeValues.Constitution } + { "Consitution", AttributeValues.Constitution }, + { "Other", AttributeValues.Free }, + { "other", AttributeValues.Free }, }) ]; diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorAttribute.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorAttribute.cs index fa30e37..d797eb6 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorAttribute.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorAttribute.cs @@ -9,13 +9,13 @@ public class AonprdProcessorAttribute(string name, string type, string[] depende public readonly IEnumerable Dependencies = dependencies; - public AonprdProcessorAttribute(string type) : this(type, type, ["trait"]) + public AonprdProcessorAttribute(string type) : this(type, type, ["trait", "source"]) { } public AonprdProcessorAttribute(string type, string[] dependencies) : this(type, type, dependencies) { } - public AonprdProcessorAttribute(string name, string type) : this(name, type, ["trait"]) + public AonprdProcessorAttribute(string name, string type) : this(name, type, ["trait", "source"]) { } } diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorCollection.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorCollection.cs index 864594c..7654688 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorCollection.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorCollection.cs @@ -31,7 +31,7 @@ internal class AonprdProcessorCollection AonprdProcessorAttribute attribute = type.GetCustomAttribute()!; - ConstructorInfo constructor = type.GetConstructor([typeof(ProcessorInput)])!; + ConstructorInfo constructor = type.GetConstructor([typeof(AonprdProcessorInput)])!; ProcessorItem? collision = Items.FirstOrDefault(i => i.Attribute.Name == attribute.Name); if (collision is not null) diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorInput.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorInput.cs index 3bf56c4..3ec718b 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorInput.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/AonprdProcessorInput.cs @@ -15,4 +15,80 @@ internal class AonprdProcessorInput(JObject input) : ProcessorInput(input) return base.Enum(value); } } + + public ActionStruct ResolveActionString(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 "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; + } + + public class ActionStruct + { + public int Actions = 0; + public int MaxActions = 0; + public bool IsPassive = false; + public bool IsReaction = false; + public bool IsFreeAction = false; + } + } diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/ActionProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/ActionProcessor.cs index 5bfeb64..41b0471 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/ActionProcessor.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/ActionProcessor.cs @@ -1,75 +1,31 @@ using Newtonsoft.Json.Linq; +using Pf2eModel.Model; using Pf2eModel.Model.Enum; namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors; [AonprdProcessor("action")] -internal class ActionProcessor(ProcessorInput input) : AbstractProcessor(input) +internal class ActionProcessor(AonprdProcessorInput input) : AbstractProcessor(input) { public override EntityType Type => EntityType.Action; public override Pf2eModel.Model.Structure.Action Object { get; } = new(); + protected override void Add() => Context.Actions.Add(Object); + public override void Process() { base.Process(); - switch (Input.GetOptional("actions")) - { - case "Single Action": - Object.Actions = Object.MaxActions = 1; - break; + AonprdProcessorInput.ActionStruct action = Input.ResolveActionString(Input.GetOptional("actions") ?? ""); - case "Two Actions": - Object.Actions = Object.MaxActions = 2; - break; - - case "Three Actions": - Object.Actions = Object.MaxActions = 3; - break; - - case "Reaction": - Object.IsReaction = true; - break; - - case "Free Action": - Object.IsFreeAction = false; - break; - - case "Single Action to Three Actions": - case "Single Action or more Actions": - Object.Actions = 1; - Object.MaxActions = 3; - break; - - case "Single Action or Two Actions": - case "Single Action to Two Actions": - Object.Actions = 1; - Object.MaxActions = 2; - break; - - case "Reaction or One Action": - Object.IsReaction = true; - Object.Actions = Object.MaxActions = 1; - break; - - case "Free Action or One Action": - Object.IsFreeAction = false; - Object.Actions = Object.MaxActions = 1; - break; - - default: - Object.IsPassive = true; - break; - } - - Object.Extra = new JObject() - { - { "school", Input.GetOptional("school") }, - - }.ToString(); - - Context.Actions.Add(Object); + Object.Actions = action.Actions; + Object.MaxActions = action.MaxActions; + Object.IsFreeAction = action.IsFreeAction; + Object.IsPassive = action.IsPassive; + Object.IsReaction = action.IsReaction; +; + Object.Extra = GenerateExtra("school"); } protected override string GetDescription() diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AncestryProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AncestryProcessor.cs index 83c4143..006f6ba 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AncestryProcessor.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/AncestryProcessor.cs @@ -9,11 +9,13 @@ using System.Text.RegularExpressions; namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors; [AonprdProcessor("ancestry", ["trait", "language"])] -internal class AncestryProcessor(ProcessorInput input) : AbstractProcessor(input) +internal class AncestryProcessor(AonprdProcessorInput input) : AbstractProcessor(input) { - public override EntityType Type { get; } = EntityType.Ancestry; + public override EntityType Type => EntityType.Ancestry; - public override Ancestry Object { get; } = new Ancestry(); + public override Ancestry Object { get; } = new(); + + protected override void Add() => Context.Ancestries.Add(Object); public override void Process() { @@ -21,7 +23,7 @@ internal class AncestryProcessor(ProcessorInput input) : AbstractProcessor(input if (type != "Ancestry") { - return; + throw new SkipItemException(Input.GetRequired("name"), "not an ancestry"); } base.Process(); @@ -66,13 +68,4 @@ internal class AncestryProcessor(ProcessorInput input) : AbstractProcessor(input } } - - - protected override string GetDescription() - => base.GetDescription() + AddedDescription([ - "source_markdown", - "summary_markdown", - "trait_markdown", - "search_markdown" - ]); } \ No newline at end of file diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/BackgroundProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/BackgroundProcessor.cs new file mode 100644 index 0000000..830df34 --- /dev/null +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/BackgroundProcessor.cs @@ -0,0 +1,50 @@ +using Newtonsoft.Json.Linq; +using Pf2eModel.Model; +using Pf2eModel.Model.Enum; +using Pf2eModel.Model.Structure; +using Pf2eModel.Model.Structure.BackgroundRelation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors; + +[AonprdProcessor("background")] +internal class BackgroundProcessor(AonprdProcessorInput input) : AbstractProcessor(input) +{ + public override EntityType Type => EntityType.Background; + + public override Background Object { get; } = new(); + + protected override void Add() => Context.Backgrounds.Add(Object); + + public override void Process() + { + base.Process(); + + foreach (JToken token in Input.GetOptional("attribute") ?? []) + { + BackgroundBoost boost = new() + { + Background = Object, + Attribute = Input.Enum(token.ToString()) + }; + + Object.BackgroundBoosts.Add(boost); + Context.BackgroundBoosts.Add(boost); + } + + } + + + protected override string GetDescription() + => base.GetDescription() + AddedDescription([ + "feat_markdown", + "summary_markdown", + "skill_markdown", + "prerequisite_markdown", + ]); +} + diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/ClassProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/ClassProcessor.cs new file mode 100644 index 0000000..755c062 --- /dev/null +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/ClassProcessor.cs @@ -0,0 +1,195 @@ +using Microsoft.Extensions.Options; +using Newtonsoft.Json.Linq; +using Pf2eModel.Model; +using Pf2eModel.Model.Common; +using Pf2eModel.Model.Enum; +using Pf2eModel.Model.Structure; +using Pf2eModel.Model.Structure.ClassRelation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors; + +[AonprdProcessor("class", ["trait", "source", "skill"])] +internal class ClassProcessor(AonprdProcessorInput input) : AbstractProcessor(input) +{ + public override EntityType Type => EntityType.Class; + + public override Class Object { get; } = new(); + + protected override void Add() => Context.Classes.Add(Object); + + public override void Process() + { + base.Process(); + + Object.Hp = Convert.ToInt32(Input.GetRequired("hp_raw")); + + AttributeValues[] attributes = Input.GetRequired("attribute") + .Select(token => Input.Enum(token.ToString())) + .ToArray(); + + foreach (AttributeValues attribute in attributes) + { + ClassKeyAbility classKeyAbility = new ClassKeyAbility() + { + Class = Object, + Value = attribute + }; + + Context.ClassKeyAbilities.Add(classKeyAbility); + Object.ClassKeyAbilities.Add(classKeyAbility); + } + + ClassTraining[] classTrainings = + [ + .. ProcessTraining(Input.GetRequired("attack_proficiency"), TrainingType.Weapon), + .. ProcessTraining(Input.GetRequired("defense_proficiency"), TrainingType.Armor), + .. GetSkillTrainings(), + .. GetSaveTrainings(), + ]; + + foreach (ClassTraining classTraining in classTrainings) + { + Context.ClassTrainings.Add(classTraining); + Object.ClassTrainings.Add(classTraining); + } + + JArray tradition = Input.GetOptional("tradition") ?? []; + + switch (tradition.Count) + { + case 0: + Object.Spellcasting = false; + Object.Tradition = SpellTradition.None; + break; + case 1: + Object.Spellcasting = true; + Object.Tradition = Input.Enum(tradition[0].ToString()); + break; + default: + Object.Spellcasting = true; + Object.Tradition = SpellTradition.All; + break; + } + } + + protected ICollection GetSkillTrainings() + { + string[] skillNames = Input.GetRequired("skill_proficiency") + .Select(token => token.ToString()) + .ToArray(); + + Training[] skills = Context.Trainings.Where(t => skillNames.Contains(t.Name)).ToArray(); + + return skills.Select(skill => new ClassTraining() + { + Class = Object, + Training = skill, + Stage = TrainingStage.Trained, + }).ToArray(); + } + + protected ICollection ProcessTraining(JArray array, TrainingType type) + { + const string pattern = @"^(.*?) in\s+(?:the)?\s*(.*)$"; + List trainings = []; + + foreach (string value in array.Select(token => token.ToString())) + { + MatchCollection m = Regex.Matches(value, pattern); + + if (m.Count == 0) + { + throw new Exception($"Can't parse training string '{value}'"); + } + + TrainingStage stage = Input.Enum(m[0].Groups[1].Value); + + string[] parts = GetTrainingString(m[0].Groups[2].Value); + + foreach (string part in parts) + { + Training? training = Context.Trainings + .FirstOrDefault(t => t.Name == part && t.Type == type); + + if (training == null) + { + training = new Training() + { + Name = part, + Type = type, + }; + + Context.Trainings.Add(training); + } + + ClassTraining classTraining = new() + { + Class = Object, + Training = training, + Stage = stage + }; + + trainings.Add(classTraining); + } + } + + return trainings; + } + + protected string[] GetTrainingString(string value) + { + if (value.StartsWith("favored weapon of your deity")) + { + return ["Favored weapon of your deity"]; + } + + if (value == "simple and martial weapons") + { + return ["Simple weapon", "Martial weapon"]; + } + + return Regex.Split(value, @"\s*(?:,|and)\s*") + .Where(s => s != "") + .Select(s => string.Concat(s[0].ToString().ToUpper(), s.AsSpan(1))) + .ToArray(); + ; + } + + protected ICollection GetSaveTrainings() + { + Dictionary result = Context.Trainings + .Where(t => t.Type == TrainingType.Save) + .ToDictionary(t => t.Name); + + foreach (string name in new[] { "Will", "Fortitude", "Reflex", "Perception" }) + { + if (result.ContainsKey(name)) + { + continue; + } + + Training training = new() { Name = 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, + Stage = Input.EnumRequired($"{pair.Key.ToLower()}_proficiency"), + }; + + return classTraining; + }).ToList(); + } +} diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/FeatProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/FeatProcessor.cs new file mode 100644 index 0000000..3ef0132 --- /dev/null +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/FeatProcessor.cs @@ -0,0 +1,61 @@ +using Newtonsoft.Json.Linq; +using Pf2eModel.Model.Enum; +using Pf2eModel.Model.Structure; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors; + +[AonprdProcessor("feat", ["trait", "source", "skill"])] +internal class FeatProcessor(AonprdProcessorInput input) : AbstractProcessor(input) +{ + public override EntityType Type => EntityType.Feat; + + public override Feat Object { get; } = new(); + + protected override void Add() => Context.Feats.Add(Object); + + public override void Process() + { + base.Process(); + + Object.Level = Input.GetRequired("level"); + + + AonprdProcessorInput.ActionStruct action = Input.ResolveActionString(Input.GetOptional("actions") ?? ""); + Object.Actions = action.Actions; + Object.MaxActions = action.MaxActions; + Object.IsFreeAction = action.IsFreeAction; + Object.IsPassive = action.IsPassive; + Object.IsReaction = action.IsReaction; + + + + + + Object.Extra = GenerateExtra( + "archetype", + "element", + "heighten", + "heighten_group", + "heighten_level", + "school", + "frequency" + ); + + + } + + protected override string GetDescription() + => base.GetDescription() + AddedDescription([ + "cost_markdown", + "feat_markdown", + "summary_markdown", + "prerequisite_markdown", + "requirement_markdown", + "trigger_markdown" + ]); +} diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/LanguageProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/LanguageProcessor.cs index 67c76db..db40f4f 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/LanguageProcessor.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/LanguageProcessor.cs @@ -4,10 +4,16 @@ using Pf2eModel.Model.Structure; namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors; [AonprdProcessor("language")] -internal class LanguageProcessor(ProcessorInput input) : AbstractProcessor(input) +internal class LanguageProcessor(AonprdProcessorInput input) : AbstractProcessor(input) { - public override EntityType Type { get; } = EntityType.Language; + public override EntityType Type => EntityType.Language; - public override Language Object { get; } = new Language(); + public override Language Object { get; } = new(); + protected override void Add() => Context.Languages.Add(Object); + + public override void Process() + { + base.Process(); + } } \ No newline at end of file diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/SourceProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/SourceProcessor.cs new file mode 100644 index 0000000..ba7df75 --- /dev/null +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/SourceProcessor.cs @@ -0,0 +1,35 @@ +using Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder; +using Pf2eModel.Model; +using Pf2eModel.Model.Base.Source; +using Pf2eModel.Model.Enum; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors; + +[AonprdProcessor("source", new string[] { })] +internal class SourceProcessor(AonprdProcessorInput input) : AbstractProcessor(input) +{ + public override EntityType Type => EntityType.Unknown; + + public override IEntity Object => null; + + protected override void Add() { } + + public override void Process() + { + // base.Process(); + + Source source = new() + { + Name = Input.GetRequired("name"), + Category = Input.EnumRequired("primary_source_category"), + ReleaseDate = DateOnly.Parse(Input.GetRequired("release_date")), + }; + + Context.Sources.Add(source); + } +} diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/TrainingProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/TrainingProcessor.cs new file mode 100644 index 0000000..0bb204c --- /dev/null +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/TrainingProcessor.cs @@ -0,0 +1,34 @@ +using Pf2eModel.Model.Base.Source; +using Pf2eModel.Model.Enum; +using Pf2eModel.Model; +using Pf2eModel.Model.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors; + +[AonprdProcessor("skill", new string[] { })] +internal class TrainingProcessor(AonprdProcessorInput input) : AbstractProcessor(input) +{ + public override EntityType Type => EntityType.Unknown; + + public override IEntity Object => null; + + protected override void Add() { } + + public override void Process() + { + // base.Process(); + + Training training = new() + { + Name = Input.GetRequired("name"), + Type = TrainingType.Skill, + }; + + Context.Trainings.Add(training); + } +} diff --git a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/TraitProcessor.cs b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/TraitProcessor.cs index d63854f..251e713 100644 --- a/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/TraitProcessor.cs +++ b/Pf2eDataScrapper/Importers/Implementations/Aonprd/DataBuilder/Processors/TraitProcessor.cs @@ -4,12 +4,14 @@ using Pf2eModel.Model.Structure; namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors; [AonprdProcessor("trait", new string[] { })] -internal class TraitProcessor(ProcessorInput input) : AbstractProcessor(input) +internal class TraitProcessor(AonprdProcessorInput input) : AbstractProcessor(input) { public override EntityType Type => EntityType.Trait; public override Trait Object { get; } = new(); + protected override void Add() => Context.Traits.Add(Object); + public override void Process() { base.Process(); diff --git a/Pf2eModel/Migrations/20250418174520_1.Designer.cs b/Pf2eModel/Migrations/20250420145024_1.Designer.cs similarity index 95% rename from Pf2eModel/Migrations/20250418174520_1.Designer.cs rename to Pf2eModel/Migrations/20250420145024_1.Designer.cs index 7f76cbf..50d4a81 100644 --- a/Pf2eModel/Migrations/20250418174520_1.Designer.cs +++ b/Pf2eModel/Migrations/20250420145024_1.Designer.cs @@ -13,7 +13,7 @@ using Pf2eModel.Model.Enum; namespace Pf2eModel.Migrations { [DbContext(typeof(Pf2eDbContext))] - [Migration("20250418174520_1")] + [Migration("20250420145024_1")] partial class _1 { /// @@ -25,7 +25,6 @@ namespace Pf2eModel.Migrations .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "action_category", new[] { "unknown", "offensive", "defensive", "interaction", "familiar", "army_tactic", "army_war_action", "kingdom_activity", "kingdom_feat", "kingdom_feature" }); - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "action_type", new[] { "none", "1_action", "2_actions", "3_actions", "1-3_actions", "1-2_actions" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "alias_type", new[] { "legacy", "english", "legacy_english", "hobby", "other" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "ancestry_vision", new[] { "normal", "low-light-vision", "dark-vision" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "attribute_values", new[] { "free", "str", "dex", "con", "int", "wis", "cha" }); @@ -35,7 +34,7 @@ namespace Pf2eModel.Migrations NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "deity_fonts", new[] { "none", "heal", "harm", "any" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "deity_sanctification", new[] { "holy", "unholy", "any" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_rarity", new[] { "common", "uncommon", "rare", "unique" }); - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_type", new[] { "unknown", "trait", "action", "ancestry", "background", "backpack", "campaign_feature", "class", "condition", "deity", "feat", "heritage", "spell", "language" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_type", new[] { "unknown", "trait", "action", "ancestry", "archetype", "background", "backpack", "campaign_feature", "class", "condition", "deity", "feat", "heritage", "spell", "language" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "feat_action_type", new[] { "passive", "action", "reaction", "free" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "feat_category", new[] { "ancestryfeature", "classfeature", "calling", "class", "skill", "general", "ancestry", "bonus", "deityboon", "curse", "pfsboon", "campaign_feature" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "size", new[] { "tiny", "small", "medium", "large" }); @@ -435,13 +434,18 @@ namespace Pf2eModel.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("Key") + b.Property("Name") .IsRequired() .HasMaxLength(255) .HasColumnType("character varying(255)") - .HasColumnName("key") + .HasColumnName("name") .HasColumnOrder(2); + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type") + .HasColumnOrder(3); + b.HasKey("Id") .HasName("pk_trainings"); @@ -485,11 +489,6 @@ namespace Pf2eModel.Migrations .HasColumnName("max_actions") .HasColumnOrder(4); - b.Property("Type") - .HasColumnType("action_type") - .HasColumnName("type") - .HasColumnOrder(2); - b.HasKey("Id") .HasName("pk_actions"); @@ -616,6 +615,38 @@ namespace Pf2eModel.Migrations b.ToTable("ancestry_languages", (string)null); }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Archetype", b => + { + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("id") + .HasColumnOrder(1); + + b.Property("DedicationFeatId") + .HasColumnType("integer") + .HasColumnName("dedication_feat_id") + .HasColumnOrder(3); + + b.Property("Extra") + .HasColumnType("text") + .HasColumnName("extra") + .HasColumnOrder(4); + + b.Property("Level") + .HasColumnType("integer") + .HasColumnName("level") + .HasColumnOrder(2); + + b.HasKey("Id") + .HasName("pk_archetype"); + + b.HasIndex("DedicationFeatId") + .IsUnique() + .HasDatabaseName("ix_archetype_dedication_feat_id"); + + b.ToTable("archetype", (string)null); + }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Background", b => { b.Property("Id") @@ -632,10 +663,13 @@ namespace Pf2eModel.Migrations modelBuilder.Entity("Pf2eModel.Model.Structure.BackgroundRelation.BackgroundBoost", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("integer") .HasColumnName("id") .HasColumnOrder(1); + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + b.Property("Attribute") .HasColumnType("attribute_values") .HasColumnName("attribute") @@ -725,7 +759,7 @@ namespace Pf2eModel.Migrations b.Property("AdditionalTrainedSkills") .HasColumnType("integer") .HasColumnName("additional_trained_skills") - .HasColumnOrder(6); + .HasColumnOrder(7); b.Property("Hp") .HasColumnType("integer") @@ -742,6 +776,11 @@ namespace Pf2eModel.Migrations .HasColumnName("spellcasting") .HasColumnOrder(5); + b.Property("Tradition") + .HasColumnType("integer") + .HasColumnName("tradition") + .HasColumnOrder(6); + b.HasKey("Id") .HasName("pk_classes"); @@ -840,8 +879,8 @@ namespace Pf2eModel.Migrations .HasColumnName("name") .HasColumnOrder(4); - b.Property("Stage") - .HasColumnType("integer") + b.Property("Stage") + .HasColumnType("training_stage") .HasColumnName("stage") .HasColumnOrder(5); @@ -1050,7 +1089,12 @@ namespace Pf2eModel.Migrations b.Property("Actions") .HasColumnType("integer") .HasColumnName("actions") - .HasColumnOrder(4); + .HasColumnOrder(5); + + b.Property("ArchetypeId") + .HasColumnType("integer") + .HasColumnName("archetype_id") + .HasColumnOrder(10); b.Property("Category") .HasColumnType("action_category") @@ -1060,42 +1104,39 @@ namespace Pf2eModel.Migrations b.Property("Extra") .HasColumnType("text") .HasColumnName("extra") - .HasColumnOrder(10); + .HasColumnOrder(11); + + b.Property("IsFreeAction") + .HasColumnType("boolean") + .HasColumnName("is_free_action") + .HasColumnOrder(8); + + b.Property("IsPassive") + .HasColumnType("boolean") + .HasColumnName("is_passive") + .HasColumnOrder(9); + + b.Property("IsReaction") + .HasColumnType("boolean") + .HasColumnName("is_reaction") + .HasColumnOrder(7); b.Property("Level") .HasColumnType("integer") .HasColumnName("level") - .HasColumnOrder(5); + .HasColumnOrder(4); - b.Property("LevelTaken") + b.Property("MaxActions") .HasColumnType("integer") - .HasColumnName("level_taken") + .HasColumnName("max_actions") .HasColumnOrder(6); - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("location") - .HasColumnOrder(8); - - b.Property("MaxTakable") - .HasColumnType("integer") - .HasColumnName("max_takable") - .HasColumnOrder(7); - - b.Property("OnlyLevel1") - .HasColumnType("boolean") - .HasColumnName("only_level1") - .HasColumnOrder(9); - - b.Property("Type") - .HasColumnType("action_type") - .HasColumnName("type") - .HasColumnOrder(2); - b.HasKey("Id") .HasName("pk_feats"); + b.HasIndex("ArchetypeId") + .HasDatabaseName("ix_feats_archetype_id"); + b.ToTable("feats", (string)null); }); @@ -1628,6 +1669,27 @@ namespace Pf2eModel.Migrations b.Navigation("Language"); }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Archetype", b => + { + b.HasOne("Pf2eModel.Model.Structure.Feat", "DedicationFeat") + .WithOne() + .HasForeignKey("Pf2eModel.Model.Structure.Archetype", "DedicationFeatId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_archetype_feats_dedication_feat_id"); + + b.HasOne("Pf2eModel.Model.Base.Entity", "Entity") + .WithOne() + .HasForeignKey("Pf2eModel.Model.Structure.Archetype", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_archetype_entities_id"); + + b.Navigation("DedicationFeat"); + + b.Navigation("Entity"); + }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Background", b => { b.HasOne("Pf2eModel.Model.Base.Entity", "Entity") @@ -1841,6 +1903,13 @@ namespace Pf2eModel.Migrations modelBuilder.Entity("Pf2eModel.Model.Structure.Feat", b => { + b.HasOne("Pf2eModel.Model.Structure.Archetype", "Archetype") + .WithMany("Feats") + .HasForeignKey("ArchetypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_feats_archetype_archetype_id"); + b.HasOne("Pf2eModel.Model.Base.Entity", "Entity") .WithOne() .HasForeignKey("Pf2eModel.Model.Structure.Feat", "Id") @@ -1848,6 +1917,8 @@ namespace Pf2eModel.Migrations .IsRequired() .HasConstraintName("fk_feats_entities_id"); + b.Navigation("Archetype"); + b.Navigation("Entity"); }); @@ -2000,6 +2071,11 @@ namespace Pf2eModel.Migrations b.Navigation("Heritages"); }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Archetype", b => + { + b.Navigation("Feats"); + }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Background", b => { b.Navigation("BackgroundBoosts"); diff --git a/Pf2eModel/Migrations/20250418174520_1.cs b/Pf2eModel/Migrations/20250420145024_1.cs similarity index 94% rename from Pf2eModel/Migrations/20250418174520_1.cs rename to Pf2eModel/Migrations/20250420145024_1.cs index fdf01b4..09ec62f 100644 --- a/Pf2eModel/Migrations/20250418174520_1.cs +++ b/Pf2eModel/Migrations/20250420145024_1.cs @@ -15,7 +15,6 @@ namespace Pf2eModel.Migrations { migrationBuilder.AlterDatabase() .Annotation("Npgsql:Enum:action_category", "unknown,offensive,defensive,interaction,familiar,army_tactic,army_war_action,kingdom_activity,kingdom_feat,kingdom_feature") - .Annotation("Npgsql:Enum:action_type", "none,1_action,2_actions,3_actions,1-3_actions,1-2_actions") .Annotation("Npgsql:Enum:alias_type", "legacy,english,legacy_english,hobby,other") .Annotation("Npgsql:Enum:ancestry_vision", "normal,low-light-vision,dark-vision") .Annotation("Npgsql:Enum:attribute_values", "free,str,dex,con,int,wis,cha") @@ -25,7 +24,7 @@ namespace Pf2eModel.Migrations .Annotation("Npgsql:Enum:deity_fonts", "none,heal,harm,any") .Annotation("Npgsql:Enum:deity_sanctification", "holy,unholy,any") .Annotation("Npgsql:Enum:entity_rarity", "common,uncommon,rare,unique") - .Annotation("Npgsql:Enum:entity_type", "unknown,trait,action,ancestry,background,backpack,campaign_feature,class,condition,deity,feat,heritage,spell,language") + .Annotation("Npgsql:Enum:entity_type", "unknown,trait,action,ancestry,archetype,background,backpack,campaign_feature,class,condition,deity,feat,heritage,spell,language") .Annotation("Npgsql:Enum:feat_action_type", "passive,action,reaction,free") .Annotation("Npgsql:Enum:feat_category", "ancestryfeature,classfeature,calling,class,skill,general,ancestry,bonus,deityboon,curse,pfsboon,campaign_feature") .Annotation("Npgsql:Enum:size", "tiny,small,medium,large") @@ -120,7 +119,8 @@ namespace Pf2eModel.Migrations { id = table.Column(type: "integer", nullable: false) .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - key = table.Column(type: "character varying(255)", maxLength: 255, nullable: false) + name = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), + type = table.Column(type: "integer", nullable: false) }, constraints: table => { @@ -132,7 +132,6 @@ namespace Pf2eModel.Migrations columns: table => new { id = table.Column(type: "integer", nullable: false), - type = table.Column(type: "action_type", nullable: false), actions = table.Column(type: "integer", nullable: true), max_actions = table.Column(type: "integer", nullable: true), is_reaction = table.Column(type: "boolean", nullable: false), @@ -197,6 +196,7 @@ namespace Pf2eModel.Migrations hp = table.Column(type: "integer", nullable: false), perception = table.Column(type: "integer", nullable: false), spellcasting = table.Column(type: "boolean", nullable: false), + tradition = table.Column(type: "integer", nullable: false), additional_trained_skills = table.Column(type: "integer", nullable: false) }, constraints: table => @@ -269,32 +269,6 @@ namespace Pf2eModel.Migrations onDelete: ReferentialAction.Cascade); }); - migrationBuilder.CreateTable( - name: "feats", - columns: table => new - { - id = table.Column(type: "integer", nullable: false), - type = table.Column(type: "action_type", nullable: false), - category = table.Column(type: "action_category", nullable: false), - actions = table.Column(type: "integer", nullable: true), - level = table.Column(type: "integer", nullable: false), - level_taken = table.Column(type: "integer", nullable: true), - max_takable = table.Column(type: "integer", nullable: true), - location = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), - only_level1 = table.Column(type: "boolean", nullable: true), - extra = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("pk_feats", x => x.id); - table.ForeignKey( - name: "fk_feats_entities_id", - column: x => x.id, - principalTable: "entities", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - migrationBuilder.CreateTable( name: "languages", columns: table => new @@ -529,7 +503,8 @@ namespace Pf2eModel.Migrations name: "background_boosts", columns: table => new { - id = table.Column(type: "integer", nullable: false), + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), background_id = table.Column(type: "integer", nullable: false), attribute = table.Column(type: "attribute_values", nullable: false) }, @@ -652,7 +627,7 @@ namespace Pf2eModel.Migrations class_id = table.Column(type: "integer", nullable: false), training_id = table.Column(type: "integer", nullable: true), name = table.Column(type: "character varying(255)", maxLength: 255, nullable: true), - stage = table.Column(type: "integer", nullable: false) + stage = table.Column(type: "training_stage", nullable: false) }, constraints: table => { @@ -754,26 +729,6 @@ namespace Pf2eModel.Migrations onDelete: ReferentialAction.Cascade); }); - migrationBuilder.CreateTable( - name: "feat_prerequisites", - columns: table => new - { - id = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - feat_id = table.Column(type: "integer", nullable: false), - value = table.Column(type: "character varying(255)", maxLength: 255, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("pk_feat_prerequisites", x => x.id); - table.ForeignKey( - name: "fk_feat_prerequisites_feats_feat_id", - column: x => x.feat_id, - principalTable: "feats", - principalColumn: "id", - onDelete: ReferentialAction.Cascade); - }); - migrationBuilder.CreateTable( name: "ancestry_languages", columns: table => new @@ -938,6 +893,78 @@ namespace Pf2eModel.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "archetype", + columns: table => new + { + id = table.Column(type: "integer", nullable: false), + level = table.Column(type: "integer", nullable: false), + dedication_feat_id = table.Column(type: "integer", nullable: false), + extra = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_archetype", x => x.id); + table.ForeignKey( + name: "fk_archetype_entities_id", + column: x => x.id, + principalTable: "entities", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "feats", + columns: table => new + { + id = table.Column(type: "integer", nullable: false), + category = table.Column(type: "action_category", nullable: false), + level = table.Column(type: "integer", nullable: false), + actions = table.Column(type: "integer", nullable: true), + max_actions = table.Column(type: "integer", nullable: true), + is_reaction = table.Column(type: "boolean", nullable: false), + is_free_action = table.Column(type: "boolean", nullable: false), + is_passive = table.Column(type: "boolean", nullable: false), + archetype_id = table.Column(type: "integer", nullable: false), + extra = table.Column(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("pk_feats", x => x.id); + table.ForeignKey( + name: "fk_feats_archetype_archetype_id", + column: x => x.archetype_id, + principalTable: "archetype", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "fk_feats_entities_id", + column: x => x.id, + principalTable: "entities", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "feat_prerequisites", + columns: table => new + { + id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + feat_id = table.Column(type: "integer", nullable: false), + value = table.Column(type: "character varying(255)", maxLength: 255, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_feat_prerequisites", x => x.id); + table.ForeignKey( + name: "fk_feat_prerequisites_feats_feat_id", + column: x => x.feat_id, + principalTable: "feats", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateIndex( name: "ix_ancestry_boosts_ancestry_id", table: "ancestry_boosts", @@ -953,6 +980,12 @@ namespace Pf2eModel.Migrations table: "ancestry_languages", column: "language_id"); + migrationBuilder.CreateIndex( + name: "ix_archetype_dedication_feat_id", + table: "archetype", + column: "dedication_feat_id", + unique: true); + migrationBuilder.CreateIndex( name: "ix_background_boosts_background_id", table: "background_boosts", @@ -1048,6 +1081,11 @@ namespace Pf2eModel.Migrations table: "feat_prerequisites", column: "feat_id"); + migrationBuilder.CreateIndex( + name: "ix_feats_archetype_id", + table: "feats", + column: "archetype_id"); + migrationBuilder.CreateIndex( name: "ix_heritages_ancestry_id", table: "heritages", @@ -1072,11 +1110,31 @@ namespace Pf2eModel.Migrations name: "ix_spell_defenses_spell_id", table: "spell_defenses", column: "spell_id"); + + migrationBuilder.AddForeignKey( + name: "fk_archetype_feats_dedication_feat_id", + table: "archetype", + column: "dedication_feat_id", + principalTable: "feats", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); } /// protected override void Down(MigrationBuilder migrationBuilder) { + migrationBuilder.DropForeignKey( + name: "fk_archetype_entities_id", + table: "archetype"); + + migrationBuilder.DropForeignKey( + name: "fk_feats_entities_id", + table: "feats"); + + migrationBuilder.DropForeignKey( + name: "fk_archetype_feats_dedication_feat_id", + table: "archetype"); + migrationBuilder.DropTable( name: "actions"); @@ -1188,9 +1246,6 @@ namespace Pf2eModel.Migrations migrationBuilder.DropTable( name: "traits"); - migrationBuilder.DropTable( - name: "feats"); - migrationBuilder.DropTable( name: "ancestries"); @@ -1202,6 +1257,12 @@ namespace Pf2eModel.Migrations migrationBuilder.DropTable( name: "entities"); + + migrationBuilder.DropTable( + name: "feats"); + + migrationBuilder.DropTable( + name: "archetype"); } } } diff --git a/Pf2eModel/Migrations/Pf2eDbContextModelSnapshot.cs b/Pf2eModel/Migrations/Pf2eDbContextModelSnapshot.cs index 825fbd2..789fd1a 100644 --- a/Pf2eModel/Migrations/Pf2eDbContextModelSnapshot.cs +++ b/Pf2eModel/Migrations/Pf2eDbContextModelSnapshot.cs @@ -22,7 +22,6 @@ namespace Pf2eModel.Migrations .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "action_category", new[] { "unknown", "offensive", "defensive", "interaction", "familiar", "army_tactic", "army_war_action", "kingdom_activity", "kingdom_feat", "kingdom_feature" }); - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "action_type", new[] { "none", "1_action", "2_actions", "3_actions", "1-3_actions", "1-2_actions" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "alias_type", new[] { "legacy", "english", "legacy_english", "hobby", "other" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "ancestry_vision", new[] { "normal", "low-light-vision", "dark-vision" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "attribute_values", new[] { "free", "str", "dex", "con", "int", "wis", "cha" }); @@ -32,7 +31,7 @@ namespace Pf2eModel.Migrations NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "deity_fonts", new[] { "none", "heal", "harm", "any" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "deity_sanctification", new[] { "holy", "unholy", "any" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_rarity", new[] { "common", "uncommon", "rare", "unique" }); - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_type", new[] { "unknown", "trait", "action", "ancestry", "background", "backpack", "campaign_feature", "class", "condition", "deity", "feat", "heritage", "spell", "language" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "entity_type", new[] { "unknown", "trait", "action", "ancestry", "archetype", "background", "backpack", "campaign_feature", "class", "condition", "deity", "feat", "heritage", "spell", "language" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "feat_action_type", new[] { "passive", "action", "reaction", "free" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "feat_category", new[] { "ancestryfeature", "classfeature", "calling", "class", "skill", "general", "ancestry", "bonus", "deityboon", "curse", "pfsboon", "campaign_feature" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "size", new[] { "tiny", "small", "medium", "large" }); @@ -432,13 +431,18 @@ namespace Pf2eModel.Migrations NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("Key") + b.Property("Name") .IsRequired() .HasMaxLength(255) .HasColumnType("character varying(255)") - .HasColumnName("key") + .HasColumnName("name") .HasColumnOrder(2); + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type") + .HasColumnOrder(3); + b.HasKey("Id") .HasName("pk_trainings"); @@ -482,11 +486,6 @@ namespace Pf2eModel.Migrations .HasColumnName("max_actions") .HasColumnOrder(4); - b.Property("Type") - .HasColumnType("action_type") - .HasColumnName("type") - .HasColumnOrder(2); - b.HasKey("Id") .HasName("pk_actions"); @@ -613,6 +612,38 @@ namespace Pf2eModel.Migrations b.ToTable("ancestry_languages", (string)null); }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Archetype", b => + { + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("id") + .HasColumnOrder(1); + + b.Property("DedicationFeatId") + .HasColumnType("integer") + .HasColumnName("dedication_feat_id") + .HasColumnOrder(3); + + b.Property("Extra") + .HasColumnType("text") + .HasColumnName("extra") + .HasColumnOrder(4); + + b.Property("Level") + .HasColumnType("integer") + .HasColumnName("level") + .HasColumnOrder(2); + + b.HasKey("Id") + .HasName("pk_archetype"); + + b.HasIndex("DedicationFeatId") + .IsUnique() + .HasDatabaseName("ix_archetype_dedication_feat_id"); + + b.ToTable("archetype", (string)null); + }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Background", b => { b.Property("Id") @@ -629,10 +660,13 @@ namespace Pf2eModel.Migrations modelBuilder.Entity("Pf2eModel.Model.Structure.BackgroundRelation.BackgroundBoost", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("integer") .HasColumnName("id") .HasColumnOrder(1); + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + b.Property("Attribute") .HasColumnType("attribute_values") .HasColumnName("attribute") @@ -722,7 +756,7 @@ namespace Pf2eModel.Migrations b.Property("AdditionalTrainedSkills") .HasColumnType("integer") .HasColumnName("additional_trained_skills") - .HasColumnOrder(6); + .HasColumnOrder(7); b.Property("Hp") .HasColumnType("integer") @@ -739,6 +773,11 @@ namespace Pf2eModel.Migrations .HasColumnName("spellcasting") .HasColumnOrder(5); + b.Property("Tradition") + .HasColumnType("integer") + .HasColumnName("tradition") + .HasColumnOrder(6); + b.HasKey("Id") .HasName("pk_classes"); @@ -837,8 +876,8 @@ namespace Pf2eModel.Migrations .HasColumnName("name") .HasColumnOrder(4); - b.Property("Stage") - .HasColumnType("integer") + b.Property("Stage") + .HasColumnType("training_stage") .HasColumnName("stage") .HasColumnOrder(5); @@ -1047,7 +1086,12 @@ namespace Pf2eModel.Migrations b.Property("Actions") .HasColumnType("integer") .HasColumnName("actions") - .HasColumnOrder(4); + .HasColumnOrder(5); + + b.Property("ArchetypeId") + .HasColumnType("integer") + .HasColumnName("archetype_id") + .HasColumnOrder(10); b.Property("Category") .HasColumnType("action_category") @@ -1057,42 +1101,39 @@ namespace Pf2eModel.Migrations b.Property("Extra") .HasColumnType("text") .HasColumnName("extra") - .HasColumnOrder(10); + .HasColumnOrder(11); + + b.Property("IsFreeAction") + .HasColumnType("boolean") + .HasColumnName("is_free_action") + .HasColumnOrder(8); + + b.Property("IsPassive") + .HasColumnType("boolean") + .HasColumnName("is_passive") + .HasColumnOrder(9); + + b.Property("IsReaction") + .HasColumnType("boolean") + .HasColumnName("is_reaction") + .HasColumnOrder(7); b.Property("Level") .HasColumnType("integer") .HasColumnName("level") - .HasColumnOrder(5); + .HasColumnOrder(4); - b.Property("LevelTaken") + b.Property("MaxActions") .HasColumnType("integer") - .HasColumnName("level_taken") + .HasColumnName("max_actions") .HasColumnOrder(6); - b.Property("Location") - .HasMaxLength(255) - .HasColumnType("character varying(255)") - .HasColumnName("location") - .HasColumnOrder(8); - - b.Property("MaxTakable") - .HasColumnType("integer") - .HasColumnName("max_takable") - .HasColumnOrder(7); - - b.Property("OnlyLevel1") - .HasColumnType("boolean") - .HasColumnName("only_level1") - .HasColumnOrder(9); - - b.Property("Type") - .HasColumnType("action_type") - .HasColumnName("type") - .HasColumnOrder(2); - b.HasKey("Id") .HasName("pk_feats"); + b.HasIndex("ArchetypeId") + .HasDatabaseName("ix_feats_archetype_id"); + b.ToTable("feats", (string)null); }); @@ -1625,6 +1666,27 @@ namespace Pf2eModel.Migrations b.Navigation("Language"); }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Archetype", b => + { + b.HasOne("Pf2eModel.Model.Structure.Feat", "DedicationFeat") + .WithOne() + .HasForeignKey("Pf2eModel.Model.Structure.Archetype", "DedicationFeatId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_archetype_feats_dedication_feat_id"); + + b.HasOne("Pf2eModel.Model.Base.Entity", "Entity") + .WithOne() + .HasForeignKey("Pf2eModel.Model.Structure.Archetype", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_archetype_entities_id"); + + b.Navigation("DedicationFeat"); + + b.Navigation("Entity"); + }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Background", b => { b.HasOne("Pf2eModel.Model.Base.Entity", "Entity") @@ -1838,6 +1900,13 @@ namespace Pf2eModel.Migrations modelBuilder.Entity("Pf2eModel.Model.Structure.Feat", b => { + b.HasOne("Pf2eModel.Model.Structure.Archetype", "Archetype") + .WithMany("Feats") + .HasForeignKey("ArchetypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_feats_archetype_archetype_id"); + b.HasOne("Pf2eModel.Model.Base.Entity", "Entity") .WithOne() .HasForeignKey("Pf2eModel.Model.Structure.Feat", "Id") @@ -1845,6 +1914,8 @@ namespace Pf2eModel.Migrations .IsRequired() .HasConstraintName("fk_feats_entities_id"); + b.Navigation("Archetype"); + b.Navigation("Entity"); }); @@ -1997,6 +2068,11 @@ namespace Pf2eModel.Migrations b.Navigation("Heritages"); }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Archetype", b => + { + b.Navigation("Feats"); + }); + modelBuilder.Entity("Pf2eModel.Model.Structure.Background", b => { b.Navigation("BackgroundBoosts"); diff --git a/Pf2eModel/Model/Common/Training.cs b/Pf2eModel/Model/Common/Training.cs index 9cc629e..e80e640 100644 --- a/Pf2eModel/Model/Common/Training.cs +++ b/Pf2eModel/Model/Common/Training.cs @@ -1,4 +1,5 @@ -using System.ComponentModel.DataAnnotations; +using Pf2eModel.Model.Enum; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace Pf2eModel.Model.Common; @@ -12,5 +13,8 @@ public partial class Training [Column(Order = 2)] [MaxLength(Pf2eDbContext.NameLength)] - public string Key { get; set; } = null!; + public string Name { get; set; } = null!; + + [Column(Order = 3)] + public TrainingType Type { get; set; } } diff --git a/Pf2eModel/Model/Enum/ActionType.cs b/Pf2eModel/Model/Enum/ActionType.cs deleted file mode 100644 index 0f5e845..0000000 --- a/Pf2eModel/Model/Enum/ActionType.cs +++ /dev/null @@ -1,24 +0,0 @@ -using NpgsqlTypes; - -namespace Pf2eModel.Model.Enum; - -public enum ActionType -{ - [PgName("none")] - None, - - [PgName("1_action")] - SingleAction, - - [PgName("2_actions")] - TwoActions, - - [PgName("3_actions")] - ThreeActions, - - [PgName("1-3_actions")] - SingleToThreeActions, - - [PgName("1-2_actions")] - SingleToTwoActions, -} \ No newline at end of file diff --git a/Pf2eModel/Model/Enum/EntityType.cs b/Pf2eModel/Model/Enum/EntityType.cs index 5abddc0..9d0311a 100644 --- a/Pf2eModel/Model/Enum/EntityType.cs +++ b/Pf2eModel/Model/Enum/EntityType.cs @@ -16,6 +16,9 @@ public enum EntityType [PgName("ancestry")] Ancestry, + [PgName("archetype")] + Archetype, + [PgName("background")] Background, diff --git a/Pf2eModel/Model/Enum/SpellTradition.cs b/Pf2eModel/Model/Enum/SpellTradition.cs new file mode 100644 index 0000000..b9082f2 --- /dev/null +++ b/Pf2eModel/Model/Enum/SpellTradition.cs @@ -0,0 +1,24 @@ +using NpgsqlTypes; + +namespace Pf2eModel.Model.Enum; + +public enum SpellTradition +{ + [PgName("none")] + None, + + [PgName("divine")] + Divine, + + [PgName("occult")] + Occult, + + [PgName("arcane")] + Arcane, + + [PgName("primal")] + Primal, + + [PgName("all")] + All, +} \ No newline at end of file diff --git a/Pf2eModel/Model/Enum/TrainingType.cs b/Pf2eModel/Model/Enum/TrainingType.cs new file mode 100644 index 0000000..5aa18b1 --- /dev/null +++ b/Pf2eModel/Model/Enum/TrainingType.cs @@ -0,0 +1,23 @@ +using NpgsqlTypes; + +namespace Pf2eModel.Model.Enum; +public enum TrainingType +{ + [PgName("perception")] + Perception, + + [PgName("skill")] + Skill, + + [PgName("lore")] + Lore, + + [PgName("weapon")] + Weapon, + + [PgName("armor")] + Armor, + + [PgName("save")] + Save, +} diff --git a/Pf2eModel/Model/Structure/Action.cs b/Pf2eModel/Model/Structure/Action.cs index d7bfbed..913e3a3 100644 --- a/Pf2eModel/Model/Structure/Action.cs +++ b/Pf2eModel/Model/Structure/Action.cs @@ -12,9 +12,6 @@ public partial class Action : IEntity [Column(Order = 1)] public int Id { get; set; } - [Column(Order = 2)] - public ActionType Type { get; set; } - [Column(Order = 3)] public int? Actions { get; set; } = null; diff --git a/Pf2eModel/Model/Structure/AncestryRelation/AncestryBoost.cs b/Pf2eModel/Model/Structure/AncestryRelation/AncestryBoost.cs index 71699fd..78f55d8 100644 --- a/Pf2eModel/Model/Structure/AncestryRelation/AncestryBoost.cs +++ b/Pf2eModel/Model/Structure/AncestryRelation/AncestryBoost.cs @@ -1,4 +1,5 @@ -using System.ComponentModel.DataAnnotations; +using Newtonsoft.Json; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace Pf2eModel.Model.Structure.AncestryRelation; @@ -19,5 +20,6 @@ public partial class AncestryBoost [Column(Order = 4)] public Enum.AttributeValues Value { get; set; } + [JsonIgnore] public virtual Ancestry Ancestry { get; set; } = null!; } diff --git a/Pf2eModel/Model/Structure/Archetype.cs b/Pf2eModel/Model/Structure/Archetype.cs new file mode 100644 index 0000000..90a61aa --- /dev/null +++ b/Pf2eModel/Model/Structure/Archetype.cs @@ -0,0 +1,32 @@ +using Pf2eModel.Model.Base; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Pf2eModel.Model.Structure; + +public class Archetype : IEntity +{ + [Key] + [Column(Order = 1)] + public int Id { get; set; } + + public Entity Entity { get; set; } = null!; + + [Column(Order = 2)] + public int Level { get; set; } + + [Column(Order = 3)] + public int DedicationFeatId { get; set; } + + [Column(Order = 4)] + public string? Extra { get; set; } + + public Feat DedicationFeat { get; set; } = null!; + + public virtual ICollection Feats { get; set; } = []; +} diff --git a/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundBoost.cs b/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundBoost.cs index 7f81f3c..7e74e1e 100644 --- a/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundBoost.cs +++ b/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundBoost.cs @@ -1,4 +1,5 @@ -using Pf2eModel.Model.Enum; +using Newtonsoft.Json; +using Pf2eModel.Model.Enum; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -7,7 +8,7 @@ namespace Pf2eModel.Model.Structure.BackgroundRelation; public partial class BackgroundBoost { [Key] - [DatabaseGenerated(DatabaseGeneratedOption.None)] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] [Column(Order = 1)] public int Id { get; set; } @@ -17,5 +18,6 @@ public partial class BackgroundBoost [Column(Order = 3)] public AttributeValues Attribute { get; set; } + [JsonIgnore] public virtual Background Background { get; set; } = null!; } diff --git a/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundItem.cs b/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundItem.cs index 161a15b..ea914a5 100644 --- a/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundItem.cs +++ b/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundItem.cs @@ -1,4 +1,5 @@ using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json; using Pf2eModel.Model.Base; using System.ComponentModel.DataAnnotations.Schema; @@ -16,6 +17,7 @@ public partial class BackgroundItem [Column(Order = 3)] public int? Level { get; set; } + [JsonIgnore] public virtual Background Background { get; set; } = null!; public virtual Entity Entity { get; set; } = null!; diff --git a/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundTraining.cs b/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundTraining.cs index bf77009..f7d8388 100644 --- a/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundTraining.cs +++ b/Pf2eModel/Model/Structure/BackgroundRelation/BackgroundTraining.cs @@ -1,4 +1,5 @@ -using Pf2eModel.Model.Common; +using Newtonsoft.Json; +using Pf2eModel.Model.Common; using Pf2eModel.Model.Enum; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -21,6 +22,7 @@ public partial class BackgroundTraining [Column(Order = 4)] public TrainingStage Level { get; set; } + [JsonIgnore] public virtual Background Background { get; set; } = null!; public virtual Training Training { get; set; } = null!; diff --git a/Pf2eModel/Model/Structure/Class.cs b/Pf2eModel/Model/Structure/Class.cs index 6d03c91..66776aa 100644 --- a/Pf2eModel/Model/Structure/Class.cs +++ b/Pf2eModel/Model/Structure/Class.cs @@ -13,7 +13,6 @@ public partial class Class : IEntity [Column(Order = 1)] public int Id { get; set; } - [Column(Order = 2)] public Entity Entity { get; set; } = null!; [Column(Order = 3)] @@ -26,6 +25,9 @@ public partial class Class : IEntity public bool Spellcasting { get; set; } [Column(Order = 6)] + public SpellTradition Tradition { get; set; } + + [Column(Order = 7)] public int AdditionalTrainedSkills { get; set; } public virtual ICollection ClassKeyAbilities { get; set; } = []; diff --git a/Pf2eModel/Model/Structure/ClassRelation/ClassKeyAbility.cs b/Pf2eModel/Model/Structure/ClassRelation/ClassKeyAbility.cs index 5f4ad43..a2529c6 100644 --- a/Pf2eModel/Model/Structure/ClassRelation/ClassKeyAbility.cs +++ b/Pf2eModel/Model/Structure/ClassRelation/ClassKeyAbility.cs @@ -1,4 +1,5 @@ -using Pf2eModel.Model.Enum; +using Newtonsoft.Json; +using Pf2eModel.Model.Enum; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -17,5 +18,6 @@ public partial class ClassKeyAbility [Column(Order = 3)] public AttributeValues Value { get; set; } + [JsonIgnore] public virtual Class Class { get; set; } = null!; } diff --git a/Pf2eModel/Model/Structure/ClassRelation/ClassProgression.cs b/Pf2eModel/Model/Structure/ClassRelation/ClassProgression.cs index 24b40a1..1d8b3ac 100644 --- a/Pf2eModel/Model/Structure/ClassRelation/ClassProgression.cs +++ b/Pf2eModel/Model/Structure/ClassRelation/ClassProgression.cs @@ -1,4 +1,5 @@ -using Pf2eModel.Model.Base; +using Newtonsoft.Json; +using Pf2eModel.Model.Base; using Pf2eModel.Model.Enum; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -23,6 +24,7 @@ public partial class ClassProgression [Column(Order = 5)] public int? EntityId { get; set; } + [JsonIgnore] public virtual Class Class { get; set; } = null!; public virtual Entity? Entity { get; set; } diff --git a/Pf2eModel/Model/Structure/ClassRelation/ClassTraining.cs b/Pf2eModel/Model/Structure/ClassRelation/ClassTraining.cs index e0aa598..18541fb 100644 --- a/Pf2eModel/Model/Structure/ClassRelation/ClassTraining.cs +++ b/Pf2eModel/Model/Structure/ClassRelation/ClassTraining.cs @@ -1,4 +1,6 @@ -using Pf2eModel.Model.Common; +using Newtonsoft.Json; +using Pf2eModel.Model.Common; +using Pf2eModel.Model.Enum; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -22,8 +24,9 @@ public partial class ClassTraining public string? Name { get; set; } [Column(Order = 5)] - public int Stage { get; set; } + public TrainingStage Stage { get; set; } + [JsonIgnore] public virtual Class Class { get; set; } = null!; public virtual Training? Training { get; set; } diff --git a/Pf2eModel/Model/Structure/Feat.cs b/Pf2eModel/Model/Structure/Feat.cs index 298213c..e6f9059 100644 --- a/Pf2eModel/Model/Structure/Feat.cs +++ b/Pf2eModel/Model/Structure/Feat.cs @@ -16,33 +16,34 @@ public partial class Feat : IEntity public Entity Entity { get; set; } = null!; - [Column(Order = 2)] - public ActionType Type { get; set; } - [Column(Order = 3)] public ActionCategory Category { get; set; } [Column(Order = 4)] - public int? Actions { get; set; } - - [Column(Order = 5)] public int Level { get; set; } + [Column(Order = 5)] + public int? Actions { get; set; } = null; + [Column(Order = 6)] - public int? LevelTaken { get; set; } + public int? MaxActions { get; set; } = null; [Column(Order = 7)] - public int? MaxTakable { get; set; } + public bool IsReaction { get; set; } = false; [Column(Order = 8)] - [MaxLength(255)] - public string? Location { get; set; } + public bool IsFreeAction { get; set; } = false; [Column(Order = 9)] - public bool? OnlyLevel1 { get; set; } + public bool IsPassive { get; set; } = false; [Column(Order = 10)] + public int ArchetypeId { get; set; } + + [Column(Order = 11)] public string? Extra { get; set; } + public Archetype Archetype { get; set; } = null!; + public virtual ICollection FeatPrerequisites { get; set; } = []; } diff --git a/Pf2eModel/Pf2eDbContext.cs b/Pf2eModel/Pf2eDbContext.cs index dfa3e0f..21034cf 100644 --- a/Pf2eModel/Pf2eDbContext.cs +++ b/Pf2eModel/Pf2eDbContext.cs @@ -125,7 +125,6 @@ public partial class Pf2eDbContext : DbContext .MapEnum() .MapEnum() .MapEnum() - .MapEnum() .MapEnum() .MapEnum() .MapEnum() diff --git a/Pf2eModel/Pf2eDbContextModel.cs b/Pf2eModel/Pf2eDbContextModel.cs index dfe5d36..f7f5a04 100644 --- a/Pf2eModel/Pf2eDbContextModel.cs +++ b/Pf2eModel/Pf2eDbContextModel.cs @@ -38,7 +38,6 @@ public partial class Pf2eDbContext .HasPostgresEnum() .HasPostgresEnum() .HasPostgresEnum() - .HasPostgresEnum() .HasPostgresEnum() .HasPostgresEnum() .HasPostgresEnum() @@ -171,6 +170,20 @@ public partial class Pf2eDbContext .OnDelete(DeleteBehavior.Cascade); }); + // Archetype + modelBuilder.Entity(entity => + { + BindEntity(entity); + + entity.HasOne(a => a.DedicationFeat).WithOne() + .HasForeignKey(a => a.DedicationFeatId) + .OnDelete(DeleteBehavior.Cascade); + + entity.HasMany(a => a.Feats).WithOne(f => f.Archetype) + .HasForeignKey(f => f.ArchetypeId) + .OnDelete(DeleteBehavior.Cascade); + }); + // Background modelBuilder.Entity(entity => { diff --git a/Pf2eViewer/EntityConverter.cs b/Pf2eViewer/EntityConverter.cs index 1b853de..bf16cfe 100644 --- a/Pf2eViewer/EntityConverter.cs +++ b/Pf2eViewer/EntityConverter.cs @@ -24,6 +24,11 @@ internal class EntityConverter : JsonConverter foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(source)) { + if (property.Attributes.OfType().Any()) + { + continue; + } + object? v = property.GetValue(source); dictionary.Add(property.Name, v); } diff --git a/Pf2eViewer/MainViewForm.cs b/Pf2eViewer/MainViewForm.cs index 11f4e40..28f2f58 100644 --- a/Pf2eViewer/MainViewForm.cs +++ b/Pf2eViewer/MainViewForm.cs @@ -1,4 +1,5 @@ -using Microsoft.EntityFrameworkCore; +using LinqToDB.Tools; +using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; @@ -7,6 +8,7 @@ using Pf2eModel; using Pf2eModel.Model; using Pf2eModel.Model.Base; using Pf2eModel.Model.Enum; +using static LinqToDB.Common.Configuration; namespace Pf2eViewer; @@ -31,7 +33,7 @@ public partial class MainViewForm : Form TypesListBox.SelectedIndex = 0; } - public const int PerPage = 20; + public const int PerPage = 30; public int Count; @@ -50,6 +52,7 @@ public partial class MainViewForm : Form private void UpdateTreeView() { + EntityTreeView.Nodes.Clear(); EntityType type = (EntityType) TypesListBox.SelectedItem!; Count = Context.Entities.Count(e => e.Type == type); @@ -63,14 +66,6 @@ public partial class MainViewForm : Form EntityGridView.DataSource = Context.Entities .Where(e => e.Type == (EntityType) TypesListBox.SelectedItem) .OrderBy(e => e.Id) - .Include(e => e.Sources) - .ThenInclude(s => s.Source) - .Include(e => e.Aliases) - .Include(e => e.Keywords) - .Include(e => e.Externals) - .ThenInclude(x => x.Target) - .Include(e => e.Traits) - .ThenInclude(t => t.Entity) .Select(e => new EntityGridRow(e)) .Skip((Page - 1) * PerPage) .Take(PerPage) @@ -99,22 +94,18 @@ public partial class MainViewForm : Form { Page = 1; } - private void PrevPageButton_Click(object sender, EventArgs e) { Page--; } - private void NextPageButton_Click(object sender, EventArgs e) { Page++; } - private void LastPageButton_Click(object sender, EventArgs e) { Page = MaxPage; } - private void PageTextBox_KeyPress(object sender, KeyPressEventArgs e) { if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar)) @@ -141,13 +132,42 @@ public partial class MainViewForm : Form EntityGridRow data = (EntityGridRow) row.DataBoundItem; - string json = SerializeEntity(data.GetEntity()); + ViewEntity(data.Id); + } + + public void ViewEntity(int id) + { + EntityTreeView.Nodes.Clear(); + + Entity? entity = Context.Entities + .Where(e => e.Id == id && e.Type == (EntityType) TypesListBox.SelectedItem!) + .Include(e => e.Sources) + .ThenInclude(s => s.Source) + .Include(e => e.Aliases) + .Include(e => e.Keywords) + .Include(e => e.Externals) + .ThenInclude(x => x.Target) + .Include(e => e.Traits) + .ThenInclude(t => t.Entity) + .FirstOrDefault() + ; + + if (entity == null) + { + DescriptionTextBox.Text = "Not found"; + return; + } + + + string json = SerializeEntity(entity); JsonToTreeview(EntityTreeView, json, "Entity"); - DescriptionTextBox.Text = data.GetEntity().Description.Replace("\\r", "").Replace("\\n", "\\r\\n"); + DescriptionTextBox.Text = entity.Description.Replace("\\r", "").Replace("\\n", "\\r\\n"); } + + public string SerializeEntity(Entity entity) { JsonSerializerSettings settings = new() @@ -161,21 +181,40 @@ public partial class MainViewForm : Form string result = JsonConvert.SerializeObject(entity, settings); Type type = EntityOfTypeAttribute.Resolve(entity); - string subResult = JsonConvert.SerializeObject(ResolveEntity(entity), settings); + string subResult = JsonConvert.SerializeObject(ResolveSubEntity(entity), settings); return result[..^1] + $",\"SubEntity\":{subResult}}}"; } - public IEntity? ResolveEntity(Entity entity) + public IEntity? ResolveSubEntity(Entity entity) { switch (entity.Type) { case EntityType.Ancestry: return Context.Ancestries + .Include(a => a.AncestryBoosts) .FirstOrDefault(e => e.Id == entity.Id); - } - return null; + case EntityType.Background: + return Context.Backgrounds + .Include(b => b.BackgroundBoosts) + .Include(b => b.BackgroundSkills) + .ThenInclude(t => t.Training) + .Include(b => b.BackgroundItems) + .FirstOrDefault(e => e.Id == entity.Id); + + case EntityType.Class: + return Context.Classes + .Include(c => c.ClassKeyAbilities) + .Include(c => c.ClassTrainings) + .ThenInclude(t => t.Training) + .Include(c => c.ClassProgressions) + .FirstOrDefault(c => c.Id == entity.Id); + + default: + Type type = EntityOfTypeAttribute.Resolve(entity); + return (IEntity?) Context.Find(type, entity.Id); + } } public static void JsonToTreeview(TreeView treeView, string jsonString, string rootName) diff --git a/README.md b/README.md index fa6afe6..8f3b046 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ schema.AddValue(data); // Добавление данных ## Aonprd (Архивы Нефиса) -Готово: **4** из 70 +Готово: **5** из 70 ### Общее - [x] action.yaml @@ -97,7 +97,7 @@ schema.AddValue(data); // Добавление данных - [ ] eidolon.yaml - [ ] element.yaml - [ ] epithet.yaml -- [ ] feat.yaml +- [x] feat.yaml - [ ] hazard.yaml - [ ] hellknight-order.yaml - [ ] heritage.yaml @@ -125,8 +125,8 @@ schema.AddValue(data); // Добавление данных - [ ] rules.yaml - [ ] sidebar.yaml - [ ] skill-general-action.yaml -- [ ] skill.yaml -- [ ] source.yaml +- [x] skill.yaml +- [x] source.yaml - [ ] spell.yaml - [ ] style.yaml - [ ] subconscious-mind.yaml