Работа над импортом заклинаний

This commit is contained in:
2025-05-05 19:23:43 +04:00
parent 2c1756cef6
commit fc5d68ca1f
26 changed files with 696 additions and 87 deletions
+2 -1
View File
@@ -46,4 +46,5 @@
<s:Boolean x:Key="/Default/Housekeeping/UpgradeFromExceptionReport/DefaultReporterBehaviorChanged/@EntryValue">True</s:Boolean> <s:Boolean x:Key="/Default/Housekeeping/UpgradeFromExceptionReport/DefaultReporterBehaviorChanged/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Housekeeping/UpgradeFromExceptionReport/UpgradePerformed/@EntryValue">True</s:Boolean> <s:Boolean x:Key="/Default/Housekeeping/UpgradeFromExceptionReport/UpgradePerformed/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/Housekeeping/WhatsNewShown/WhatsNewShownIndexedEntry/=RC/@EntryIndexedValue">2025.1.0.0</s:String> <s:String x:Key="/Default/Housekeeping/WhatsNewShown/WhatsNewShownIndexedEntry/=RC/@EntryIndexedValue">2025.1.0.0</s:String>
<s:String x:Key="/Default/Housekeeping/WhatsNewShown/WhatsNewShownIndexedEntry/=RS0/@EntryIndexedValue">2025.1.0.0</s:String></wpf:ResourceDictionary> <s:String x:Key="/Default/Housekeeping/WhatsNewShown/WhatsNewShownIndexedEntry/=RS0/@EntryIndexedValue">2025.1.0.0</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Aonprd/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
@@ -52,8 +52,26 @@ internal class AonprdProcessorCollection
} }
} }
private void CheckDependencies()
{
foreach (ProcessorItem item in Items)
{
foreach (string dependency in item.Attribute.Dependencies)
{
if (Items.All(i => i.Attribute.Name != dependency))
{
throw new(
$"Dependency '{dependency}' for processor '{item.Attribute.Name}' not found."
);
}
}
}
}
private void SortItems() private void SortItems()
{ {
CheckDependencies();
Dictionary<string, int> priorities = []; Dictionary<string, int> priorities = [];
while (priorities.Count < Items.Count) while (priorities.Count < Items.Count)
@@ -60,6 +60,12 @@ internal class AonprdProcessorInput(JObject input) : ProcessorInput(input)
result.MaxActions = 3; result.MaxActions = 3;
break; break;
case "Two Actions to 2 rounds":
result.Actions = 2;
result.MaxActions = 3;
result.TwoRounds = true;
break;
case "Reaction or One Action": case "Reaction or One Action":
result.IsReaction = true; result.IsReaction = true;
result.Actions = result.MaxActions = 1; result.Actions = result.MaxActions = 1;
@@ -90,5 +96,6 @@ internal class AonprdProcessorInput(JObject input) : ProcessorInput(input)
public bool IsPassive; public bool IsPassive;
public bool IsReaction; public bool IsReaction;
public bool IsFreeAction; public bool IsFreeAction;
public bool TwoRounds;
} }
} }
@@ -33,6 +33,33 @@ public static class AonprdEnumResolver
{ "other", AttributeValues.Free }, { "other", AttributeValues.Free },
} }
), ),
new Solver<ActionEnum>(
new()
{
{ "Single Action", ActionEnum.SingleAction },
{ "Two Actions", ActionEnum.TwoActions },
{ "Three Actions", ActionEnum.ThreeActions },
{ "Reaction", ActionEnum.Reaction },
{ "Free Action", ActionEnum.FreeAction },
{ "Single Action to Three Actions", ActionEnum.SingleActionToThreeActions },
{ "Single Action or more Actions", ActionEnum.SingleActionToThreeActions },
{ "Single Action or Two Actions", ActionEnum.SingleActionToTwoActions },
{ "Single Action to Two Actions", ActionEnum.SingleActionToTwoActions },
{ "Two Actions or Three Actions", ActionEnum.TwoActionsToThreeActions },
{ "Two Actions to 2 rounds", ActionEnum.TwoActionsToTwoRounds },
{ "Reaction or One Action", ActionEnum.ReactionOrOneAction },
{ "Reaction or Two Actions", ActionEnum.ReactionOrTwoAction },
{ "Reaction or Three Actions", ActionEnum.ReactionOrThreeAction },
{ "Free Action or One Action", ActionEnum.FreeActionOrOneAction },
{ "1 Minute", ActionEnum.OneMinute },
{ "1 minute", ActionEnum.OneMinute },
{ "5 minutes", ActionEnum.FiveMinutes },
{ "10 minutes", ActionEnum.TenMinutes },
{ "30 minutes", ActionEnum.ThirtyMinutes },
{ "1 hour", ActionEnum.OneHour },
{ "<i>Nethys Note: No cast time was printed</i>", ActionEnum.Unknown },
}
),
]; ];
public static T Resolve<T>(string value) public static T Resolve<T>(string value)
@@ -6,6 +6,24 @@ internal partial class StringHelper
{ {
private StringHelper() { } private StringHelper() { }
public List<MarkdownLink> ParseMarkdown(string input)
{
List<MarkdownLink> links = [];
Match match = MarkdownRegex().Match(input);
if (match.Captures.Count > 0)
{
links.Add(
new()
{
Prefix = match.Groups[1].Value.Trim(),
Text = match.Groups[2].Value.Trim(),
Url = match.Groups[3].Value.Trim(),
}
);
}
return links;
}
public string ResolveSource(string input) public string ResolveSource(string input)
{ {
Match match = SourceSuffixRegex().Match(input); Match match = SourceSuffixRegex().Match(input);
@@ -16,4 +34,14 @@ internal partial class StringHelper
[GeneratedRegex(@"^\[.*?\]\(.*?\)\s+(.*)$")] [GeneratedRegex(@"^\[.*?\]\(.*?\)\s+(.*)$")]
private static partial Regex SourceSuffixRegex(); private static partial Regex SourceSuffixRegex();
[GeneratedRegex(@"(.*?)\[(.*?)\]\((.*?)\)")]
private static partial Regex MarkdownRegex();
}
internal class MarkdownLink
{
public string Prefix { get; set; } = "";
public string Text { get; set; } = "";
public string Url { get; set; } = "";
} }
@@ -1,16 +1,21 @@
using Pf2eModel.Model.Common; using Pf2eModel.Model.Common;
using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum; using Pf2eModel.Model.Enum;
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Common; namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Common;
[AonprdProcessor("skill", [])] [AonprdProcessor("skill", [])]
internal class TrainingProcessor(AonprdProcessorInput input) : AbstractProcessor(input) internal class SkillProcessor(AonprdProcessorInput input) : AbstractProcessor(input)
{ {
public Training Training = null!; public Training Training = null!;
public override void Process() public override void Process()
{ {
Training = new() { Name = Input.GetRequired<string>("name"), Type = TrainingType.Skill }; Training = new()
{
Name = new() { { LocaleType.English, Input.GetRequired<string>("name") } },
Type = TrainingType.Skill,
};
} }
public override void Save() public override void Save()
@@ -1,8 +1,15 @@
using Pf2eModel.Model.Structure; using Microsoft.EntityFrameworkCore;
using Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Helpers;
using Pf2eModel;
using Pf2eModel.Model.Base;
using Pf2eModel.Model.Common;
using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure;
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Subclasses; namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Subclasses;
[AonprdProcessor("apparition", ["class"])] [AonprdProcessor("apparition", ["class", "spell", "trainings"])]
internal class ApparitionProcessor(AonprdProcessorInput input) : AbstractSubclassProcessor(input) internal class ApparitionProcessor(AonprdProcessorInput input) : AbstractSubclassProcessor(input)
{ {
public override Subclass Object { get; } = new(); public override Subclass Object { get; } = new();
@@ -11,7 +18,54 @@ internal class ApparitionProcessor(AonprdProcessorInput input) : AbstractSubclas
public override string GroupName => "Apparition"; public override string GroupName => "Apparition";
public override void ProcessObject() { } public override void ProcessObject()
{
// Spells
string spellMd = Input.GetRequired<string>("spells_markdown");
List<string> spellUrls = StringHelper.ParseMarkdown(spellMd).Select(l => l.Url).ToList();
List<int> spellIds = Context
.EntityExternals.Where(x => spellUrls.Contains(x.Suffix))
.Select(x => x.Entity.Id)
.ToList();
List<Entity> spells = Context
.Spells.Where(s => spellIds.Contains(s.Id))
.Select(s => s.Entity)
.ToList();
foreach (Entity spellEntity in spells)
{
Object.Entities.Add(spellEntity);
}
// Trainings
string trainingMd = Input.GetRequired<string>("skill_markdown");
List<string> trainingNames = trainingMd.Split(", ").ToList();
List<Training> trainings = Context
.Trainings.Where(t => Pf2eDbContext.LocaleSearchArray(t.Name, trainingNames))
.ToList();
foreach (string name in trainingNames)
{
Training? training = trainings.FirstOrDefault(t => t.Name!.Contains(name));
training ??= new()
{
Name = new() { { LocaleType.English, name } },
Type = TrainingType.Lore,
};
Object.Trainings.Add(
new()
{
Subclass = Object,
Training = training,
Stage = TrainingStage.Trained,
}
);
}
}
protected override string GetDescription() => protected override string GetDescription() =>
base.GetDescription() base.GetDescription()
@@ -2,7 +2,7 @@
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Types; namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Types;
[AonprdProcessor("action")] // [AonprdProcessor("action")]
internal class ActionProcessor(AonprdProcessorInput input) : AbstractEntityProcessor(input) internal class ActionProcessor(AonprdProcessorInput input) : AbstractEntityProcessor(input)
{ {
public override EntityType Type => EntityType.Action; public override EntityType Type => EntityType.Action;
@@ -29,16 +29,7 @@ internal class ActionProcessor(AonprdProcessorInput input) : AbstractEntityProce
base.Process(); base.Process();
AonprdProcessorInput.ActionStruct action = Input.ResolveActionString( Object.Actions = Input.EnumOptional("actions", ActionEnum.Passive);
Input.GetOptional<string>("actions") ?? ""
);
Object.Actions = action.Actions;
Object.MaxActions = action.MaxActions;
Object.IsFreeAction = action.IsFreeAction;
Object.IsPassive = action.IsPassive;
Object.IsReaction = action.IsReaction;
Object.Extra = GenerateExtra("school"); Object.Extra = GenerateExtra("school");
} }
@@ -1,6 +1,8 @@
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Pf2eModel;
using Pf2eModel.Model.Common; using Pf2eModel.Model.Common;
using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum; using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure; using Pf2eModel.Model.Structure;
using Pf2eModel.Model.Structure.ClassRelation; using Pf2eModel.Model.Structure.ClassRelation;
@@ -82,13 +84,14 @@ internal class ClassProcessor(AonprdProcessorInput input) : AbstractEntityProces
protected ICollection<ClassTraining> GetSkillTrainings() protected ICollection<ClassTraining> GetSkillTrainings()
{ {
string[] skillNames = Input List<string> skillNames = Input
.GetRequired<JArray>("skill_proficiency") .GetRequired<JArray>("skill_proficiency")
.Select(token => token.ToString()) .Select(token => token.ToString())
.ToArray(); .ToList();
Training[] skills = Context.Trainings.Where(t => skillNames.Contains(t.Name)).ToArray(); Training[] skills = Context
// Training[] skills = Context.Trainings.Where(t => Pf2eDbContext.LocaleSearchArray(t.Name, skillNames)).ToArray(); .Trainings.Where(t => Pf2eDbContext.LocaleSearchArray(t.Name, skillNames))
.ToArray();
return skills return skills
.Select(skill => new ClassTraining() .Select(skill => new ClassTraining()
@@ -121,12 +124,16 @@ internal class ClassProcessor(AonprdProcessorInput input) : AbstractEntityProces
foreach (string part in parts) foreach (string part in parts)
{ {
Training? training = Context.Trainings.FirstOrDefault(t => Training? training = Context.Trainings.FirstOrDefault(t =>
t.Name == part && t.Type == type Pf2eDbContext.LocaleSearch(t.Name, part) && t.Type == type
); );
if (training == null) if (training == null)
{ {
training = new Training() { Name = part, Type = type }; training = new Training()
{
Name = new() { [LocaleType.English] = part },
Type = type,
};
Context.Trainings.Add(training); Context.Trainings.Add(training);
} }
@@ -160,7 +167,7 @@ internal class ClassProcessor(AonprdProcessorInput input) : AbstractEntityProces
{ {
Dictionary<string, Training> result = Context Dictionary<string, Training> result = Context
.Trainings.Where(t => t.Type == TrainingType.Save) .Trainings.Where(t => t.Type == TrainingType.Save)
.ToDictionary(t => t.Name); .ToDictionary(t => t.Name[LocaleType.English]);
foreach (string name in new[] { "Will", "Fortitude", "Reflex", "Perception" }) foreach (string name in new[] { "Will", "Fortitude", "Reflex", "Perception" })
{ {
@@ -171,7 +178,7 @@ internal class ClassProcessor(AonprdProcessorInput input) : AbstractEntityProces
Training training = new() Training training = new()
{ {
Name = name, Name = new() { [LocaleType.English] = name },
Type = (name == "Perception") ? TrainingType.Perception : TrainingType.Save, Type = (name == "Perception") ? TrainingType.Perception : TrainingType.Save,
}; };
@@ -0,0 +1,67 @@
using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure;
using Pf2eModel.Model.Structure.SpellRelation;
namespace Pf2eDataScrapper.Importers.Implementations.Aonprd.DataBuilder.Processors.Types;
[AonprdProcessor("spell")]
internal class SpellProcessor(AonprdProcessorInput input) : AbstractEntityProcessor(input)
{
public override EntityType Type => EntityType.Spell;
public override Spell Object { get; } = new();
public override void Add() => Context.Spells.Add(Object);
public override void Process()
{
base.Process();
Object.Level = Input.GetRequired<int>("level");
Object.Actions = Input.EnumOptional("actions", ActionEnum.Unknown);
Object.IsFocus = Input.GetRequired<string>("spell_type") == "Focus";
switch (Input.GetRequired<string>("spell_type"))
{
case "Focus":
Object.IsFocus = true;
break;
case "Cantrip":
Object.Level = 0;
break;
}
foreach (string areaType in Input.GetOptional<string[]>("area_type") ?? [])
{
Object.SpellAreas.Add(
new()
{
Spell = Object,
Type = Input.EnumRequired<SpellAreaType>(areaType),
Value = 0,
}
);
}
}
protected override string GetDescription() =>
base.GetDescription()
+ AddedDescription(
[
"area_raw",
"bloodline_markdown",
"deity_markdown",
"domain_markdown",
"lesson_markdown",
"mystery_markdown",
"requirement_markdown",
"summary_markdown",
"tradition_markdown",
"patron_theme_markdown",
"trigger_markdown",
"saving_throw_markdown",
"target_markdown",
]
);
}
@@ -13,7 +13,7 @@ using Pf2eModel.Model.Enum;
namespace Pf2eModel.Migrations namespace Pf2eModel.Migrations
{ {
[DbContext(typeof(Pf2eDbContext))] [DbContext(typeof(Pf2eDbContext))]
[Migration("20250428065903_1")] [Migration("20250505114131_1")]
partial class _1 partial class _1
{ {
/// <inheritdoc /> /// <inheritdoc />
@@ -417,8 +417,7 @@ namespace Pf2eModel.Migrations
b.Property<string>("Name") b.Property<string>("Name")
.IsRequired() .IsRequired()
.HasMaxLength(255) .HasColumnType("jsonb")
.HasColumnType("character varying(255)")
.HasColumnName("name") .HasColumnName("name")
.HasColumnOrder(2); .HasColumnOrder(2);
@@ -873,16 +872,10 @@ namespace Pf2eModel.Migrations
.HasColumnName("class_id") .HasColumnName("class_id")
.HasColumnOrder(2); .HasColumnOrder(2);
b.Property<string>("Name")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("name")
.HasColumnOrder(4);
b.Property<TrainingStage>("Stage") b.Property<TrainingStage>("Stage")
.HasColumnType("training_stage") .HasColumnType("training_stage")
.HasColumnName("stage") .HasColumnName("stage")
.HasColumnOrder(5); .HasColumnOrder(4);
b.Property<int?>("TrainingId") b.Property<int?>("TrainingId")
.HasColumnType("integer") .HasColumnType("integer")
@@ -901,6 +894,62 @@ namespace Pf2eModel.Migrations
b.ToTable("class_trainings", (string)null); b.ToTable("class_trainings", (string)null);
}); });
modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassProvidedEntities", b =>
{
b.Property<int>("SubclassId")
.HasColumnType("integer")
.HasColumnName("subclass_id");
b.Property<int>("EntityId")
.HasColumnType("integer")
.HasColumnName("entity_id");
b.HasKey("SubclassId", "EntityId")
.HasName("pk_subclass_provided_entities");
b.HasIndex("EntityId")
.HasDatabaseName("ix_subclass_provided_entities_entity_id");
b.ToTable("subclass_provided_entities", (string)null);
});
modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassTrainings", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.HasColumnOrder(1);
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<TrainingStage>("Stage")
.HasColumnType("training_stage")
.HasColumnName("stage")
.HasColumnOrder(4);
b.Property<int>("SubclassId")
.HasColumnType("integer")
.HasColumnName("subclass_id")
.HasColumnOrder(2);
b.Property<int>("TrainingId")
.HasColumnType("integer")
.HasColumnName("training_id")
.HasColumnOrder(3);
b.HasKey("Id")
.HasName("pk_subclass_trainings");
b.HasIndex("SubclassId")
.HasDatabaseName("ix_subclass_trainings_subclass_id");
b.HasIndex("TrainingId")
.HasDatabaseName("ix_subclass_trainings_training_id");
b.ToTable("subclass_trainings", (string)null);
});
modelBuilder.Entity("Pf2eModel.Model.Structure.Condition", b => modelBuilder.Entity("Pf2eModel.Model.Structure.Condition", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@@ -1870,6 +1919,44 @@ namespace Pf2eModel.Migrations
b.Navigation("Training"); b.Navigation("Training");
}); });
modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassProvidedEntities", b =>
{
b.HasOne("Pf2eModel.Model.Base.Entity", null)
.WithMany()
.HasForeignKey("EntityId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_subclass_provided_entities_entities_entity_id");
b.HasOne("Pf2eModel.Model.Structure.Subclass", null)
.WithMany()
.HasForeignKey("SubclassId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_subclass_provided_entities_subclasses_subclass_id");
});
modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassTrainings", b =>
{
b.HasOne("Pf2eModel.Model.Structure.Subclass", "Subclass")
.WithMany("Trainings")
.HasForeignKey("SubclassId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_subclass_trainings_subclasses_subclass_id");
b.HasOne("Pf2eModel.Model.Common.Training", "Training")
.WithMany()
.HasForeignKey("TrainingId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_subclass_trainings_trainings_training_id");
b.Navigation("Subclass");
b.Navigation("Training");
});
modelBuilder.Entity("Pf2eModel.Model.Structure.Condition", b => modelBuilder.Entity("Pf2eModel.Model.Structure.Condition", b =>
{ {
b.HasOne("Pf2eModel.Model.Base.Entity", "Entity") b.HasOne("Pf2eModel.Model.Base.Entity", "Entity")
@@ -2198,6 +2285,11 @@ namespace Pf2eModel.Migrations
b.Navigation("SpellRitual"); b.Navigation("SpellRitual");
}); });
modelBuilder.Entity("Pf2eModel.Model.Structure.Subclass", b =>
{
b.Navigation("Trainings");
});
modelBuilder.Entity("Pf2eModel.Model.Structure.SubclassGroup", b => modelBuilder.Entity("Pf2eModel.Model.Structure.SubclassGroup", b =>
{ {
b.Navigation("Subclasses"); b.Navigation("Subclasses");
@@ -120,7 +120,7 @@ namespace Pf2eModel.Migrations
{ {
id = table.Column<int>(type: "integer", nullable: false) id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
name = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: false), name = table.Column<string>(type: "jsonb", nullable: false),
type = table.Column<int>(type: "integer", nullable: false) type = table.Column<int>(type: "integer", nullable: false)
}, },
constraints: table => constraints: table =>
@@ -633,7 +633,6 @@ namespace Pf2eModel.Migrations
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
class_id = table.Column<int>(type: "integer", nullable: false), class_id = table.Column<int>(type: "integer", nullable: false),
training_id = table.Column<int>(type: "integer", nullable: true), training_id = table.Column<int>(type: "integer", nullable: true),
name = table.Column<string>(type: "character varying(255)", maxLength: 255, nullable: true),
stage = table.Column<TrainingStage>(type: "training_stage", nullable: false) stage = table.Column<TrainingStage>(type: "training_stage", nullable: false)
}, },
constraints: table => constraints: table =>
@@ -1020,6 +1019,57 @@ namespace Pf2eModel.Migrations
onDelete: ReferentialAction.Cascade); onDelete: ReferentialAction.Cascade);
}); });
migrationBuilder.CreateTable(
name: "subclass_provided_entities",
columns: table => new
{
subclass_id = table.Column<int>(type: "integer", nullable: false),
entity_id = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_subclass_provided_entities", x => new { x.subclass_id, x.entity_id });
table.ForeignKey(
name: "fk_subclass_provided_entities_entities_entity_id",
column: x => x.entity_id,
principalTable: "entities",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_subclass_provided_entities_subclasses_subclass_id",
column: x => x.subclass_id,
principalTable: "subclasses",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "subclass_trainings",
columns: table => new
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
subclass_id = table.Column<int>(type: "integer", nullable: false),
training_id = table.Column<int>(type: "integer", nullable: false),
stage = table.Column<TrainingStage>(type: "training_stage", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_subclass_trainings", x => x.id);
table.ForeignKey(
name: "fk_subclass_trainings_subclasses_subclass_id",
column: x => x.subclass_id,
principalTable: "subclasses",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "fk_subclass_trainings_trainings_training_id",
column: x => x.training_id,
principalTable: "trainings",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "ix_ancestry_boosts_ancestry_id", name: "ix_ancestry_boosts_ancestry_id",
table: "ancestry_boosts", table: "ancestry_boosts",
@@ -1171,6 +1221,21 @@ namespace Pf2eModel.Migrations
table: "subclass_groups", table: "subclass_groups",
column: "class_id"); column: "class_id");
migrationBuilder.CreateIndex(
name: "ix_subclass_provided_entities_entity_id",
table: "subclass_provided_entities",
column: "entity_id");
migrationBuilder.CreateIndex(
name: "ix_subclass_trainings_subclass_id",
table: "subclass_trainings",
column: "subclass_id");
migrationBuilder.CreateIndex(
name: "ix_subclass_trainings_training_id",
table: "subclass_trainings",
column: "training_id");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "ix_subclasses_group_id", name: "ix_subclasses_group_id",
table: "subclasses", table: "subclasses",
@@ -1268,7 +1333,10 @@ namespace Pf2eModel.Migrations
name: "spell_rituals"); name: "spell_rituals");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "subclasses"); name: "subclass_provided_entities");
migrationBuilder.DropTable(
name: "subclass_trainings");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "languages"); name: "languages");
@@ -1279,9 +1347,6 @@ namespace Pf2eModel.Migrations
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "backgrounds"); name: "backgrounds");
migrationBuilder.DropTable(
name: "trainings");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "deities"); name: "deities");
@@ -1304,11 +1369,17 @@ namespace Pf2eModel.Migrations
name: "spells"); name: "spells");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "subclass_groups"); name: "subclasses");
migrationBuilder.DropTable(
name: "trainings");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "feats"); name: "feats");
migrationBuilder.DropTable(
name: "subclass_groups");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "classes"); name: "classes");
@@ -414,8 +414,7 @@ namespace Pf2eModel.Migrations
b.Property<string>("Name") b.Property<string>("Name")
.IsRequired() .IsRequired()
.HasMaxLength(255) .HasColumnType("jsonb")
.HasColumnType("character varying(255)")
.HasColumnName("name") .HasColumnName("name")
.HasColumnOrder(2); .HasColumnOrder(2);
@@ -870,16 +869,10 @@ namespace Pf2eModel.Migrations
.HasColumnName("class_id") .HasColumnName("class_id")
.HasColumnOrder(2); .HasColumnOrder(2);
b.Property<string>("Name")
.HasMaxLength(255)
.HasColumnType("character varying(255)")
.HasColumnName("name")
.HasColumnOrder(4);
b.Property<TrainingStage>("Stage") b.Property<TrainingStage>("Stage")
.HasColumnType("training_stage") .HasColumnType("training_stage")
.HasColumnName("stage") .HasColumnName("stage")
.HasColumnOrder(5); .HasColumnOrder(4);
b.Property<int?>("TrainingId") b.Property<int?>("TrainingId")
.HasColumnType("integer") .HasColumnType("integer")
@@ -898,6 +891,62 @@ namespace Pf2eModel.Migrations
b.ToTable("class_trainings", (string)null); b.ToTable("class_trainings", (string)null);
}); });
modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassProvidedEntities", b =>
{
b.Property<int>("SubclassId")
.HasColumnType("integer")
.HasColumnName("subclass_id");
b.Property<int>("EntityId")
.HasColumnType("integer")
.HasColumnName("entity_id");
b.HasKey("SubclassId", "EntityId")
.HasName("pk_subclass_provided_entities");
b.HasIndex("EntityId")
.HasDatabaseName("ix_subclass_provided_entities_entity_id");
b.ToTable("subclass_provided_entities", (string)null);
});
modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassTrainings", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.HasColumnOrder(1);
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<TrainingStage>("Stage")
.HasColumnType("training_stage")
.HasColumnName("stage")
.HasColumnOrder(4);
b.Property<int>("SubclassId")
.HasColumnType("integer")
.HasColumnName("subclass_id")
.HasColumnOrder(2);
b.Property<int>("TrainingId")
.HasColumnType("integer")
.HasColumnName("training_id")
.HasColumnOrder(3);
b.HasKey("Id")
.HasName("pk_subclass_trainings");
b.HasIndex("SubclassId")
.HasDatabaseName("ix_subclass_trainings_subclass_id");
b.HasIndex("TrainingId")
.HasDatabaseName("ix_subclass_trainings_training_id");
b.ToTable("subclass_trainings", (string)null);
});
modelBuilder.Entity("Pf2eModel.Model.Structure.Condition", b => modelBuilder.Entity("Pf2eModel.Model.Structure.Condition", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@@ -1867,6 +1916,44 @@ namespace Pf2eModel.Migrations
b.Navigation("Training"); b.Navigation("Training");
}); });
modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassProvidedEntities", b =>
{
b.HasOne("Pf2eModel.Model.Base.Entity", null)
.WithMany()
.HasForeignKey("EntityId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_subclass_provided_entities_entities_entity_id");
b.HasOne("Pf2eModel.Model.Structure.Subclass", null)
.WithMany()
.HasForeignKey("SubclassId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_subclass_provided_entities_subclasses_subclass_id");
});
modelBuilder.Entity("Pf2eModel.Model.Structure.ClassRelation.SubclassTrainings", b =>
{
b.HasOne("Pf2eModel.Model.Structure.Subclass", "Subclass")
.WithMany("Trainings")
.HasForeignKey("SubclassId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_subclass_trainings_subclasses_subclass_id");
b.HasOne("Pf2eModel.Model.Common.Training", "Training")
.WithMany()
.HasForeignKey("TrainingId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_subclass_trainings_trainings_training_id");
b.Navigation("Subclass");
b.Navigation("Training");
});
modelBuilder.Entity("Pf2eModel.Model.Structure.Condition", b => modelBuilder.Entity("Pf2eModel.Model.Structure.Condition", b =>
{ {
b.HasOne("Pf2eModel.Model.Base.Entity", "Entity") b.HasOne("Pf2eModel.Model.Base.Entity", "Entity")
@@ -2195,6 +2282,11 @@ namespace Pf2eModel.Migrations
b.Navigation("SpellRitual"); b.Navigation("SpellRitual");
}); });
modelBuilder.Entity("Pf2eModel.Model.Structure.Subclass", b =>
{
b.Navigation("Trainings");
});
modelBuilder.Entity("Pf2eModel.Model.Structure.SubclassGroup", b => modelBuilder.Entity("Pf2eModel.Model.Structure.SubclassGroup", b =>
{ {
b.Navigation("Subclasses"); b.Navigation("Subclasses");
+10 -4
View File
@@ -7,18 +7,24 @@ namespace Pf2eModel.Model.Base.Targets;
[PrimaryKey(nameof(EntityId), nameof(TargetId))] [PrimaryKey(nameof(EntityId), nameof(TargetId))]
public class EntityExternal public class EntityExternal
{ {
[Column(Order = 0)] [Column(Order = 1)]
public int EntityId { get; set; } public int EntityId { get; set; }
[Column(Order = 1)] [Column(Order = 2)]
public int TargetId { get; set; } public int TargetId { get; set; }
[Column(Order = 2)] /*
[Column(Order = 3)]
[MaxLength(255)]
public string ExternalId { get; set; } = "";
*/
[Column(Order = 4)]
[MaxLength(255)] [MaxLength(255)]
[Comment("Часть URL до объекта. Для источников Foundry - полный UUID объекта")] [Comment("Часть URL до объекта. Для источников Foundry - полный UUID объекта")]
public string Suffix { get; set; } = ""; public string Suffix { get; set; } = "";
[Column(Order = 3)] [Column(Order = 5)]
[MaxLength(32)] [MaxLength(32)]
[Comment("Контроль версии объекта")] [Comment("Контроль версии объекта")]
public string Md5 { get; set; } = null!; public string Md5 { get; set; } = null!;
+2 -2
View File
@@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum; using Pf2eModel.Model.Enum;
namespace Pf2eModel.Model.Common; namespace Pf2eModel.Model.Common;
@@ -12,8 +13,7 @@ public class Training
public int Id { get; set; } public int Id { get; set; }
[Column(Order = 2)] [Column(Order = 2)]
[MaxLength(Pf2eDbContext.NameLength)] public LocaleString Name { get; set; } = [];
public string Name { get; set; } = null!;
[Column(Order = 3)] [Column(Order = 3)]
public TrainingType Type { get; set; } public TrainingType Type { get; set; }
+69
View File
@@ -0,0 +1,69 @@
using NpgsqlTypes;
namespace Pf2eModel.Model.Enum;
public enum ActionEnum
{
[PgName("unknown")]
Unknown,
[PgName("1")]
SingleAction,
[PgName("2")]
TwoActions,
[PgName("3")]
ThreeActions,
[PgName("reaction")]
Reaction,
[PgName("free")]
FreeAction,
[PgName("passive")]
Passive,
[PgName("other")]
Other,
[PgName("1-3")]
SingleActionToThreeActions,
[PgName("1-2")]
SingleActionToTwoActions,
[PgName("2-3")]
TwoActionsToThreeActions,
[PgName("2/2 rounds")]
TwoActionsToTwoRounds,
[PgName("reaction/1")]
ReactionOrOneAction,
[PgName("reaction/2")]
ReactionOrTwoAction,
[PgName("reaction/3")]
ReactionOrThreeAction,
[PgName("free/1")]
FreeActionOrOneAction,
[PgName("1 minute")]
OneMinute,
[PgName("5 minutes")]
FiveMinutes,
[PgName("10 minutes")]
TenMinutes,
[PgName("30 minutes")]
ThirtyMinutes,
[PgName("1 hour")]
OneHour,
}
+12
View File
@@ -24,4 +24,16 @@ public enum SpellAreaType
[PgName("cylinder")] [PgName("cylinder")]
Cylinder, Cylinder,
[PgName("varies")]
Varies,
[PgName("cuboid")]
Cuboid,
[PgName("circle")]
Circle,
[PgName("other")]
Other,
} }
+3 -15
View File
@@ -12,22 +12,10 @@ public class Action : IEntity
[Column(Order = 1)] [Column(Order = 1)]
public int Id { get; set; } public int Id { get; set; }
[Column(Order = 2)]
public ActionEnum Actions { get; set; } = ActionEnum.Unknown;
[Column(Order = 3)] [Column(Order = 3)]
public int? Actions { get; set; } = null;
[Column(Order = 4)]
public int? MaxActions { get; set; } = null;
[Column(Order = 5)]
public bool IsReaction { get; set; } = false;
[Column(Order = 6)]
public bool IsFreeAction { get; set; } = false;
[Column(Order = 6)]
public bool IsPassive { get; set; } = false;
[Column(Order = 6)]
// ReSharper disable once EntityFramework.ModelValidation.UnlimitedStringLength // ReSharper disable once EntityFramework.ModelValidation.UnlimitedStringLength
public string? Extra { get; set; } public string? Extra { get; set; }
@@ -3,7 +3,7 @@
namespace Pf2eModel.Model.Structure.ArchetypeRelation; namespace Pf2eModel.Model.Structure.ArchetypeRelation;
[PrimaryKey(nameof(ArchetypeId), nameof(FeatId))] [PrimaryKey(nameof(ArchetypeId), nameof(FeatId))]
internal class ArchetypeFeats public class ArchetypeFeats
{ {
public int ArchetypeId { get; set; } public int ArchetypeId { get; set; }
@@ -20,10 +20,6 @@ public class ClassTraining
public int? TrainingId { get; set; } public int? TrainingId { get; set; }
[Column(Order = 4)] [Column(Order = 4)]
[MaxLength(Pf2eDbContext.NameLength)]
public string? Name { get; set; }
[Column(Order = 5)]
public TrainingStage Stage { get; set; } public TrainingStage Stage { get; set; }
[JsonIgnore] [JsonIgnore]
@@ -0,0 +1,11 @@
using Microsoft.EntityFrameworkCore;
namespace Pf2eModel.Model.Structure.ClassRelation;
[PrimaryKey(nameof(SubclassId), nameof(EntityId))]
public class SubclassProvidedEntities
{
public int SubclassId { get; set; }
public int EntityId { get; set; }
}
@@ -0,0 +1,27 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Pf2eModel.Model.Common;
using Pf2eModel.Model.Enum;
namespace Pf2eModel.Model.Structure.ClassRelation;
public class SubclassTrainings
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column(Order = 1)]
public int Id { get; set; }
[Column(Order = 2)]
public int SubclassId { get; set; }
[Column(Order = 3)]
public int TrainingId { get; set; }
[Column(Order = 4)]
public TrainingStage Stage { get; set; } = TrainingStage.Trained;
public Subclass Subclass { get; set; } = null!;
public Training Training { get; set; } = null!;
}
+10 -2
View File
@@ -1,6 +1,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Pf2eModel.Model.Base; using Pf2eModel.Model.Base;
using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum; using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure.SpellRelation; using Pf2eModel.Model.Structure.SpellRelation;
@@ -20,7 +21,12 @@ public class Spell : IEntity
public int Level { get; set; } public int Level { get; set; }
[Column(Order = 3)] [Column(Order = 3)]
public int Cost { get; set; } public ActionEnum Actions { get; set; } = ActionEnum.Other;
[Column(Order = 4)]
public bool IsFocus { get; set; }
// ---
[Column(Order = 4)] [Column(Order = 4)]
public bool Counteraction { get; set; } public bool Counteraction { get; set; }
@@ -51,7 +57,9 @@ public class Spell : IEntity
[Column(Order = 11)] [Column(Order = 11)]
public bool CanHeightening { get; set; } public bool CanHeightening { get; set; }
public virtual SpellArea? SpellArea { get; set; } // ---
public virtual ICollection<SpellArea> SpellAreas { get; set; } = [];
public virtual SpellRitual? SpellRitual { get; set; } public virtual SpellRitual? SpellRitual { get; set; }
@@ -9,16 +9,19 @@ public class SpellArea
[Key] [Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)] [DatabaseGenerated(DatabaseGeneratedOption.None)]
[Column(Order = 1)] [Column(Order = 1)]
public int SpellId { get; set; } public int Id { get; set; }
[Column(Order = 2)] [Column(Order = 2)]
public int SpellId { get; set; }
[Column(Order = 3)]
[MaxLength(255)] [MaxLength(255)]
public string? Details { get; set; } public string? Details { get; set; }
[Column(Order = 3)] [Column(Order = 4)]
public SpellAreaType Type { get; set; } public SpellAreaType Type { get; set; }
[Column(Order = 4)] [Column(Order = 5)]
public int Value { get; set; } public int Value { get; set; }
public virtual Spell Spell { get; set; } = null!; public virtual Spell Spell { get; set; } = null!;
+5
View File
@@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations.Schema;
using Pf2eModel.Model.Base; using Pf2eModel.Model.Base;
using Pf2eModel.Model.Common.I18n; using Pf2eModel.Model.Common.I18n;
using Pf2eModel.Model.Enum; using Pf2eModel.Model.Enum;
using Pf2eModel.Model.Structure.ClassRelation;
namespace Pf2eModel.Model.Structure; namespace Pf2eModel.Model.Structure;
@@ -26,4 +27,8 @@ public class Subclass : IEntity
[Column(Order = 4)] [Column(Order = 4)]
// ReSharper disable once EntityFramework.ModelValidation.UnlimitedStringLength // ReSharper disable once EntityFramework.ModelValidation.UnlimitedStringLength
public string Extra { get; set; } = "{}"; public string Extra { get; set; } = "{}";
public virtual ICollection<Entity> Entities { get; set; } = [];
public virtual ICollection<SubclassTrainings> Trainings { get; set; } = [];
} }
+29 -5
View File
@@ -159,7 +159,10 @@ public partial class Pf2eDbContext
modelBuilder.Entity<Language>(entity => { }); modelBuilder.Entity<Language>(entity => { });
modelBuilder.Entity<Training>(entity => { }); modelBuilder.Entity<Training>(entity =>
{
BindLocaleString(entity, t => t.Name);
});
} }
private void DefineStructure(ModelBuilder modelBuilder) private void DefineStructure(ModelBuilder modelBuilder)
@@ -331,6 +334,28 @@ public partial class Pf2eDbContext
.WithMany(g => g.Subclasses) .WithMany(g => g.Subclasses)
.HasForeignKey(s => s.GroupId) .HasForeignKey(s => s.GroupId)
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
entity
.HasMany(e => e.Entities)
.WithMany()
.UsingEntity<SubclassProvidedEntities>(
l => l.HasOne<Entity>().WithMany().HasForeignKey(se => se.EntityId),
r => r.HasOne<Subclass>().WithMany().HasForeignKey(se => se.SubclassId)
);
entity
.HasMany(e => e.Trainings)
.WithOne(t => t.Subclass)
.HasForeignKey(t => t.SubclassId)
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<SubclassTrainings>(entity =>
{
entity
.HasOne(d => d.Subclass)
.WithMany(p => p.Trainings)
.HasForeignKey(d => d.SubclassId)
.OnDelete(DeleteBehavior.Cascade);
}); });
// Condition // Condition
@@ -413,11 +438,10 @@ public partial class Pf2eDbContext
BindEntity(entity); BindEntity(entity);
entity entity
.HasOne(e => e.SpellArea) .HasMany(e => e.SpellAreas)
.WithOne(e => e.Spell) .WithOne(e => e.Spell)
.HasForeignKey<SpellArea>(e => e.SpellId) .HasForeignKey(e => e.SpellId)
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade);
.IsRequired(false);
entity entity
.HasOne(e => e.SpellRitual) .HasOne(e => e.SpellRitual)