diff --git a/Server/DB/Documents/Account.cs b/Server/DB/Documents/Account.cs index 77e37ad..5bffbae 100644 --- a/Server/DB/Documents/Account.cs +++ b/Server/DB/Documents/Account.cs @@ -2,7 +2,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; namespace Server.DB.Documents; @@ -32,8 +31,4 @@ public class Account public byte PermissionLevel { get; set; } [Column(TypeName = "bytea")] public byte[] Salt { get; set; } public virtual ICollection Characters { get; set; } - - [DeleteBehavior(DeleteBehavior.Cascade)] - [CanBeNull] - public virtual GuildMember GuildMember { get; set; } } diff --git a/Server/DB/Documents/Character.cs b/Server/DB/Documents/Character.cs index f44abda..db7d8e0 100644 --- a/Server/DB/Documents/Character.cs +++ b/Server/DB/Documents/Character.cs @@ -2,7 +2,6 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; using Wonderking.Game.Data.Character; using Wonderking.Packets.Outgoing.Data; @@ -14,6 +13,7 @@ namespace Server.DB.Documents; public class Character { [DeleteBehavior(DeleteBehavior.Cascade)] + [Required] public virtual Account Account { get; set; } [Key] @@ -32,7 +32,6 @@ public class Character public byte Level { get; set; } [DeleteBehavior(DeleteBehavior.Cascade)] - [CanBeNull] public virtual ICollection InventoryItems { get; set; } public BaseStats BaseStats { get; set; } @@ -41,7 +40,6 @@ public class Character public int Health { get; set; } public int Mana { get; set; } - [DeleteBehavior(DeleteBehavior.Restrict)] - [CanBeNull] - public virtual Guild Guild { get; set; } + [DeleteBehavior(DeleteBehavior.Cascade)] + public virtual GuildMember GuildMember { get; set; } } diff --git a/Server/DB/Documents/GuildMember.cs b/Server/DB/Documents/GuildMember.cs index 597cbc8..c51d96b 100644 --- a/Server/DB/Documents/GuildMember.cs +++ b/Server/DB/Documents/GuildMember.cs @@ -12,9 +12,20 @@ public class GuildMember [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid Id { get; set; } + + public virtual Guid CharacterId { get; set; } + [DeleteBehavior(DeleteBehavior.Restrict)] + [ForeignKey(nameof(CharacterId))] + [Required] public virtual Character Character { get; set; } + + public virtual Guid GuildId { get; set; } + [DeleteBehavior(DeleteBehavior.Restrict)] + [ForeignKey(nameof(GuildId))] + [Required] public virtual Guild Guild { get; set; } + public GuildRank Rank { get; set; } } diff --git a/Server/DB/Documents/InventoryItem.cs b/Server/DB/Documents/InventoryItem.cs index b9f6e02..f4df3ee 100644 --- a/Server/DB/Documents/InventoryItem.cs +++ b/Server/DB/Documents/InventoryItem.cs @@ -9,6 +9,7 @@ namespace Server.DB.Documents; public class InventoryItem { [DeleteBehavior(DeleteBehavior.Restrict)] + [Required] public virtual Character Character { get; set; } [Key] diff --git a/Server/DB/Migrations/20231125112400_FixEntityRelationships.Designer.cs b/Server/DB/Migrations/20231125112400_FixEntityRelationships.Designer.cs new file mode 100644 index 0000000..42bdf25 --- /dev/null +++ b/Server/DB/Migrations/20231125112400_FixEntityRelationships.Designer.cs @@ -0,0 +1,347 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Server.DB; + +#nullable disable + +namespace Server.DB.Migrations +{ + [DbContext(typeof(WonderkingContext))] + [Migration("20231125112400_FixEntityRelationships")] + partial class FixEntityRelationships + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true) + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Server.DB.Documents.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("Password") + .HasColumnType("bytea"); + + b.Property("PermissionLevel") + .HasColumnType("smallint"); + + b.Property("Salt") + .HasColumnType("bytea"); + + b.Property("Username") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("Server.DB.Documents.Character", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("Experience") + .HasColumnType("bigint"); + + b.Property("Gender") + .HasColumnType("smallint"); + + b.Property("Health") + .HasColumnType("integer"); + + b.Property("LastXCoordinate") + .HasColumnType("smallint"); + + b.Property("LastYCoordinate") + .HasColumnType("smallint"); + + b.Property("Level") + .HasColumnType("smallint"); + + b.Property("Mana") + .HasColumnType("integer"); + + b.Property("MapId") + .HasColumnType("integer"); + + b.Property("Name") + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("PvPLevel") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Characters"); + }); + + modelBuilder.Entity("Server.DB.Documents.Guild", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .HasMaxLength(16) + .HasColumnType("character varying(16)"); + + b.Property("Notice") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Id") + .IsUnique(); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Guilds"); + }); + + modelBuilder.Entity("Server.DB.Documents.GuildMember", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("GuildId") + .HasColumnType("uuid"); + + b.Property("Rank") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("CharacterId") + .IsUnique(); + + b.HasIndex("GuildId"); + + b.HasIndex("Id") + .IsUnique(); + + b.ToTable("GuildMember"); + }); + + modelBuilder.Entity("Server.DB.Documents.InventoryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AddOption") + .HasColumnType("smallint"); + + b.Property("AddOption2") + .HasColumnType("smallint"); + + b.Property("AddOption3") + .HasColumnType("smallint"); + + b.Property("CharacterId") + .HasColumnType("uuid"); + + b.Property("Count") + .HasColumnType("integer"); + + b.Property("InventoryTab") + .HasColumnType("smallint"); + + b.Property("ItemId") + .HasColumnType("integer"); + + b.Property("Level") + .HasColumnType("smallint"); + + b.Property("Option") + .HasColumnType("smallint"); + + b.Property("Option2") + .HasColumnType("smallint"); + + b.Property("Option3") + .HasColumnType("smallint"); + + b.Property("Rarity") + .HasColumnType("smallint"); + + b.Property("Slot") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("CharacterId"); + + b.ToTable("InventoryItems"); + }); + + modelBuilder.Entity("Server.DB.Documents.Character", b => + { + b.HasOne("Server.DB.Documents.Account", "Account") + .WithMany("Characters") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.OwnsOne("Wonderking.Packets.Outgoing.Data.BaseStats", "BaseStats", b1 => + { + b1.Property("CharacterId") + .HasColumnType("uuid"); + + b1.Property("Dexterity") + .HasColumnType("smallint") + .HasAnnotation("Relational:JsonPropertyName", "dexterity"); + + b1.Property("Intelligence") + .HasColumnType("smallint") + .HasAnnotation("Relational:JsonPropertyName", "intelligence"); + + b1.Property("Luck") + .HasColumnType("smallint") + .HasAnnotation("Relational:JsonPropertyName", "luck"); + + b1.Property("Strength") + .HasColumnType("smallint") + .HasAnnotation("Relational:JsonPropertyName", "strength"); + + b1.Property("Vitality") + .HasColumnType("smallint") + .HasAnnotation("Relational:JsonPropertyName", "vitality"); + + b1.Property("Wisdom") + .HasColumnType("smallint") + .HasAnnotation("Relational:JsonPropertyName", "wisdom"); + + b1.HasKey("CharacterId"); + + b1.ToTable("Characters"); + + b1.WithOwner() + .HasForeignKey("CharacterId"); + }); + + b.OwnsOne("Wonderking.Packets.Outgoing.Data.JobData", "JobData", b1 => + { + b1.Property("CharacterId") + .HasColumnType("uuid"); + + b1.Property("FirstJob") + .HasColumnType("smallint"); + + b1.Property("FourthJob") + .HasColumnType("smallint"); + + b1.Property("SecondJob") + .HasColumnType("smallint"); + + b1.Property("ThirdJob") + .HasColumnType("smallint"); + + b1.HasKey("CharacterId"); + + b1.ToTable("Characters"); + + b1.WithOwner() + .HasForeignKey("CharacterId"); + }); + + b.Navigation("Account"); + + b.Navigation("BaseStats"); + + b.Navigation("JobData"); + }); + + modelBuilder.Entity("Server.DB.Documents.GuildMember", b => + { + b.HasOne("Server.DB.Documents.Character", "Character") + .WithOne("GuildMember") + .HasForeignKey("Server.DB.Documents.GuildMember", "CharacterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("Server.DB.Documents.Guild", "Guild") + .WithMany("GuildMembers") + .HasForeignKey("GuildId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Character"); + + b.Navigation("Guild"); + }); + + modelBuilder.Entity("Server.DB.Documents.InventoryItem", b => + { + b.HasOne("Server.DB.Documents.Character", "Character") + .WithMany("InventoryItems") + .HasForeignKey("CharacterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Character"); + }); + + modelBuilder.Entity("Server.DB.Documents.Account", b => + { + b.Navigation("Characters"); + }); + + modelBuilder.Entity("Server.DB.Documents.Character", b => + { + b.Navigation("GuildMember"); + + b.Navigation("InventoryItems"); + }); + + modelBuilder.Entity("Server.DB.Documents.Guild", b => + { + b.Navigation("GuildMembers"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Server/DB/Migrations/20231125112400_FixEntityRelationships.cs b/Server/DB/Migrations/20231125112400_FixEntityRelationships.cs new file mode 100644 index 0000000..9bfd2e8 --- /dev/null +++ b/Server/DB/Migrations/20231125112400_FixEntityRelationships.cs @@ -0,0 +1,172 @@ +// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License. + +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Server.DB.Migrations; + +/// +public partial class FixEntityRelationships : Migration +{ + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Accounts_GuildMember_GuildMemberId", + table: "Accounts"); + + migrationBuilder.DropForeignKey( + name: "FK_Characters_Guilds_GuildId", + table: "Characters"); + + migrationBuilder.DropIndex( + name: "IX_GuildMember_CharacterId", + table: "GuildMember"); + + migrationBuilder.DropIndex( + name: "IX_Characters_GuildId", + table: "Characters"); + + migrationBuilder.DropIndex( + name: "IX_Accounts_GuildMemberId", + table: "Accounts"); + + migrationBuilder.DropColumn( + name: "GuildId", + table: "Characters"); + + migrationBuilder.DropColumn( + name: "GuildMemberId", + table: "Accounts"); + + migrationBuilder.AlterColumn( + name: "CharacterId", + table: "InventoryItems", + type: "uuid", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + oldClrType: typeof(Guid), + oldType: "uuid", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "GuildId", + table: "GuildMember", + type: "uuid", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + oldClrType: typeof(Guid), + oldType: "uuid", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "CharacterId", + table: "GuildMember", + type: "uuid", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + oldClrType: typeof(Guid), + oldType: "uuid", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "AccountId", + table: "Characters", + type: "uuid", + nullable: false, + defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), + oldClrType: typeof(Guid), + oldType: "uuid", + oldNullable: true); + + migrationBuilder.CreateIndex( + name: "IX_GuildMember_CharacterId", + table: "GuildMember", + column: "CharacterId", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_GuildMember_CharacterId", + table: "GuildMember"); + + migrationBuilder.AlterColumn( + name: "CharacterId", + table: "InventoryItems", + type: "uuid", + nullable: true, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AlterColumn( + name: "GuildId", + table: "GuildMember", + type: "uuid", + nullable: true, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AlterColumn( + name: "CharacterId", + table: "GuildMember", + type: "uuid", + nullable: true, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AlterColumn( + name: "AccountId", + table: "Characters", + type: "uuid", + nullable: true, + oldClrType: typeof(Guid), + oldType: "uuid"); + + migrationBuilder.AddColumn( + name: "GuildId", + table: "Characters", + type: "uuid", + nullable: true); + + migrationBuilder.AddColumn( + name: "GuildMemberId", + table: "Accounts", + type: "uuid", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_GuildMember_CharacterId", + table: "GuildMember", + column: "CharacterId"); + + migrationBuilder.CreateIndex( + name: "IX_Characters_GuildId", + table: "Characters", + column: "GuildId"); + + migrationBuilder.CreateIndex( + name: "IX_Accounts_GuildMemberId", + table: "Accounts", + column: "GuildMemberId"); + + migrationBuilder.AddForeignKey( + name: "FK_Accounts_GuildMember_GuildMemberId", + table: "Accounts", + column: "GuildMemberId", + principalTable: "GuildMember", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_Characters_Guilds_GuildId", + table: "Characters", + column: "GuildId", + principalTable: "Guilds", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + } +} diff --git a/Server/DB/Migrations/WonderkingContextModelSnapshot.cs b/Server/DB/Migrations/WonderkingContextModelSnapshot.cs index 843efda..9568719 100644 --- a/Server/DB/Migrations/WonderkingContextModelSnapshot.cs +++ b/Server/DB/Migrations/WonderkingContextModelSnapshot.cs @@ -34,9 +34,6 @@ namespace Server.DB.Migrations b.Property("Email") .HasColumnType("text"); - b.Property("GuildMemberId") - .HasColumnType("uuid"); - b.Property("Password") .HasColumnType("bytea"); @@ -52,8 +49,6 @@ namespace Server.DB.Migrations b.HasKey("Id"); - b.HasIndex("GuildMemberId"); - b.HasIndex("Id") .IsUnique(); @@ -69,7 +64,7 @@ namespace Server.DB.Migrations .ValueGeneratedOnAdd() .HasColumnType("uuid"); - b.Property("AccountId") + b.Property("AccountId") .HasColumnType("uuid"); b.Property("Experience") @@ -78,9 +73,6 @@ namespace Server.DB.Migrations b.Property("Gender") .HasColumnType("smallint"); - b.Property("GuildId") - .HasColumnType("uuid"); - b.Property("Health") .HasColumnType("integer"); @@ -110,8 +102,6 @@ namespace Server.DB.Migrations b.HasIndex("AccountId"); - b.HasIndex("GuildId"); - b.HasIndex("Id") .IsUnique(); @@ -151,10 +141,10 @@ namespace Server.DB.Migrations .ValueGeneratedOnAdd() .HasColumnType("uuid"); - b.Property("CharacterId") + b.Property("CharacterId") .HasColumnType("uuid"); - b.Property("GuildId") + b.Property("GuildId") .HasColumnType("uuid"); b.Property("Rank") @@ -162,7 +152,8 @@ namespace Server.DB.Migrations b.HasKey("Id"); - b.HasIndex("CharacterId"); + b.HasIndex("CharacterId") + .IsUnique(); b.HasIndex("GuildId"); @@ -187,7 +178,7 @@ namespace Server.DB.Migrations b.Property("AddOption3") .HasColumnType("smallint"); - b.Property("CharacterId") + b.Property("CharacterId") .HasColumnType("uuid"); b.Property("Count") @@ -224,27 +215,13 @@ namespace Server.DB.Migrations b.ToTable("InventoryItems"); }); - modelBuilder.Entity("Server.DB.Documents.Account", b => - { - b.HasOne("Server.DB.Documents.GuildMember", "GuildMember") - .WithMany() - .HasForeignKey("GuildMemberId") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("GuildMember"); - }); - modelBuilder.Entity("Server.DB.Documents.Character", b => { b.HasOne("Server.DB.Documents.Account", "Account") .WithMany("Characters") .HasForeignKey("AccountId") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Server.DB.Documents.Guild", "Guild") - .WithMany() - .HasForeignKey("GuildId") - .OnDelete(DeleteBehavior.Restrict); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.OwnsOne("Wonderking.Packets.Outgoing.Data.BaseStats", "BaseStats", b1 => { @@ -312,22 +289,22 @@ namespace Server.DB.Migrations b.Navigation("BaseStats"); - b.Navigation("Guild"); - b.Navigation("JobData"); }); modelBuilder.Entity("Server.DB.Documents.GuildMember", b => { b.HasOne("Server.DB.Documents.Character", "Character") - .WithMany() - .HasForeignKey("CharacterId") - .OnDelete(DeleteBehavior.Restrict); + .WithOne("GuildMember") + .HasForeignKey("Server.DB.Documents.GuildMember", "CharacterId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); b.HasOne("Server.DB.Documents.Guild", "Guild") .WithMany("GuildMembers") .HasForeignKey("GuildId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.Navigation("Character"); @@ -339,7 +316,8 @@ namespace Server.DB.Migrations b.HasOne("Server.DB.Documents.Character", "Character") .WithMany("InventoryItems") .HasForeignKey("CharacterId") - .OnDelete(DeleteBehavior.Cascade); + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); b.Navigation("Character"); }); @@ -351,6 +329,8 @@ namespace Server.DB.Migrations modelBuilder.Entity("Server.DB.Documents.Character", b => { + b.Navigation("GuildMember"); + b.Navigation("InventoryItems"); }); diff --git a/Server/Program.cs b/Server/Program.cs index 212fc75..8c72a28 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -2,7 +2,6 @@ using System.Net; using System.Reflection; -using System.Text.Json; using MassTransit; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; @@ -17,7 +16,6 @@ using OpenTelemetry.Resources; using OpenTelemetry.Trace; using Server.DB; using Server.Services; -using Wonderking.Game.Mapping; var builder = Host.CreateApplicationBuilder(); #if DEBUG @@ -96,10 +94,6 @@ builder.Services.AddDbContextPool(o => .EnableSensitiveDataLogging().UseLazyLoadingProxies().UseLoggerFactory(loggerFactory); }); -builder.Services.AddSingleton( - JsonSerializer.Deserialize( - File.ReadAllText("config/character-stats.mapping.json")) ?? throw new InvalidOperationException()); - builder.Services.AddSingleton(loggerFactory); builder.Services.AddSingleton(); builder.Services.AddSingleton();