feat: add guild data to character selection and db
All checks were successful
Build, Package and Push Images / preprocess (push) Successful in 2s
Build, Package and Push Images / build (push) Successful in 25s
Build, Package and Push Images / sonarqube (push) Has been skipped
Build, Package and Push Images / sbom-scan (push) Successful in 34s
Build, Package and Push Images / container-build (push) Successful in 1m15s
Build, Package and Push Images / container-sbom-scan (push) Successful in 37s

This commit is contained in:
Timothy Schenk 2023-11-14 20:07:45 +01:00
parent 5381d78cfc
commit 4b0840b5b9
12 changed files with 623 additions and 27 deletions

View file

@ -24,4 +24,6 @@ public class Character
public JobData JobData { get; set; } public JobData JobData { get; set; }
public int Health { get; set; } public int Health { get; set; }
public int Mana { get; set; } public int Mana { get; set; }
public Guid GuildId { get; set; }
public Guild Guild { get; set; }
} }

View file

@ -0,0 +1,9 @@
namespace Server.DB.Documents;
public class Guild
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Notice { get; set; }
public ICollection<GuildMember> GuildMembers { get; set; }
}

View file

@ -0,0 +1,11 @@
namespace Server.DB.Documents;
public class GuildMember
{
public Guid Id { get; set; }
public Guid CharacterId { get; set; }
public Character Character { get; set; }
public Guid GuildId { get; set; }
public Guild Guild { get; set; }
public GuildRank Rank { get; set; }
}

View file

@ -0,0 +1,11 @@
namespace Server.DB.Documents;
public enum GuildRank : byte
{
Initiate = 0,
Member = 1,
Veteran = 2,
Elite = 3,
Officer = 4,
Master = 5
}

View file

@ -0,0 +1,327 @@
// <auto-generated />
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("20231114184404_AddGuildData")]
partial class AddGuildData
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.13")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Server.DB.Documents.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Email")
.HasColumnType("text");
b.Property<byte[]>("Password")
.HasColumnType("bytea");
b.Property<byte>("PermissionLevel")
.HasColumnType("smallint");
b.Property<byte[]>("Salt")
.HasColumnType("bytea");
b.Property<string>("Username")
.HasColumnType("varchar(20)");
b.HasKey("Id");
b.ToTable("Accounts");
});
modelBuilder.Entity("Server.DB.Documents.Character", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<long>("Experience")
.HasColumnType("bigint");
b.Property<byte>("Gender")
.HasColumnType("smallint");
b.Property<Guid>("GuildId")
.HasColumnType("uuid");
b.Property<int>("Health")
.HasColumnType("integer");
b.Property<short>("LastXCoordinate")
.HasColumnType("smallint");
b.Property<short>("LastYCoordinate")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<int>("Mana")
.HasColumnType("integer");
b.Property<int>("MapId")
.HasColumnType("integer");
b.Property<string>("Name")
.HasColumnType("varchar(20)");
b.Property<byte>("PvPLevel")
.HasColumnType("smallint");
b.Property<byte>("ServerId")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("GuildId");
b.ToTable("Characters");
});
modelBuilder.Entity("Server.DB.Documents.Guild", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Notice")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Guild");
});
modelBuilder.Entity("Server.DB.Documents.GuildMember", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<Guid>("GuildId")
.HasColumnType("uuid");
b.Property<byte>("Rank")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.HasIndex("GuildId");
b.ToTable("GuildMember");
});
modelBuilder.Entity("Server.DB.Documents.InventoryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("AddOption")
.HasColumnType("smallint");
b.Property<byte>("AddOption2")
.HasColumnType("smallint");
b.Property<byte>("AddOption3")
.HasColumnType("smallint");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<byte>("ItemType")
.HasColumnType("smallint");
b.Property<byte>("Level")
.HasColumnType("smallint");
b.Property<short>("Option")
.HasColumnType("smallint");
b.Property<short>("Option2")
.HasColumnType("smallint");
b.Property<short>("Option3")
.HasColumnType("smallint");
b.Property<byte>("Rarity")
.HasColumnType("smallint");
b.Property<byte>("Slot")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.ToTable("InventoryItem");
});
modelBuilder.Entity("Server.DB.Documents.Character", b =>
{
b.HasOne("Server.DB.Documents.Account", "Account")
.WithMany("Characters")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Server.DB.Documents.Guild", "Guild")
.WithMany()
.HasForeignKey("GuildId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.OwnsOne("Wonderking.Packets.Outgoing.BaseStats", "BaseStats", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<short>("Dexterity")
.HasColumnType("smallint");
b1.Property<short>("Intelligence")
.HasColumnType("smallint");
b1.Property<short>("Luck")
.HasColumnType("smallint");
b1.Property<short>("Strength")
.HasColumnType("smallint");
b1.Property<short>("Vitality")
.HasColumnType("smallint");
b1.Property<short>("Wisdom")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.OwnsOne("Wonderking.Packets.Outgoing.JobData", "JobData", b1 =>
{
b1.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b1.Property<byte>("FirstJob")
.HasColumnType("smallint");
b1.Property<byte>("FourthJob")
.HasColumnType("smallint");
b1.Property<byte>("SecondJob")
.HasColumnType("smallint");
b1.Property<byte>("ThirdJob")
.HasColumnType("smallint");
b1.HasKey("CharacterId");
b1.ToTable("Characters");
b1.WithOwner()
.HasForeignKey("CharacterId");
});
b.Navigation("Account");
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.Cascade)
.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("InventoryItems");
});
modelBuilder.Entity("Server.DB.Documents.Guild", b =>
{
b.Navigation("GuildMembers");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,104 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Server.DB.Migrations;
/// <inheritdoc />
public partial class AddGuildData : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "GuildId",
table: "Characters",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.CreateTable(
name: "Guild",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: true),
Notice = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Guild", x => x.Id);
});
migrationBuilder.CreateTable(
name: "GuildMember",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
CharacterId = table.Column<Guid>(type: "uuid", nullable: false),
GuildId = table.Column<Guid>(type: "uuid", nullable: false),
Rank = table.Column<byte>(type: "smallint", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_GuildMember", x => x.Id);
table.ForeignKey(
name: "FK_GuildMember_Characters_CharacterId",
column: x => x.CharacterId,
principalTable: "Characters",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_GuildMember_Guild_GuildId",
column: x => x.GuildId,
principalTable: "Guild",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Characters_GuildId",
table: "Characters",
column: "GuildId");
migrationBuilder.CreateIndex(
name: "IX_GuildMember_CharacterId",
table: "GuildMember",
column: "CharacterId");
migrationBuilder.CreateIndex(
name: "IX_GuildMember_GuildId",
table: "GuildMember",
column: "GuildId");
migrationBuilder.AddForeignKey(
name: "FK_Characters_Guild_GuildId",
table: "Characters",
column: "GuildId",
principalTable: "Guild",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Characters_Guild_GuildId",
table: "Characters");
migrationBuilder.DropTable(
name: "GuildMember");
migrationBuilder.DropTable(
name: "Guild");
migrationBuilder.DropIndex(
name: "IX_Characters_GuildId",
table: "Characters");
migrationBuilder.DropColumn(
name: "GuildId",
table: "Characters");
}
}

View file

@ -63,6 +63,9 @@ namespace Server.DB.Migrations
b.Property<byte>("Gender") b.Property<byte>("Gender")
.HasColumnType("smallint"); .HasColumnType("smallint");
b.Property<Guid>("GuildId")
.HasColumnType("uuid");
b.Property<int>("Health") b.Property<int>("Health")
.HasColumnType("integer"); .HasColumnType("integer");
@ -94,9 +97,52 @@ namespace Server.DB.Migrations
b.HasIndex("AccountId"); b.HasIndex("AccountId");
b.HasIndex("GuildId");
b.ToTable("Characters"); b.ToTable("Characters");
}); });
modelBuilder.Entity("Server.DB.Documents.Guild", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<string>("Notice")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Guild");
});
modelBuilder.Entity("Server.DB.Documents.GuildMember", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("CharacterId")
.HasColumnType("uuid");
b.Property<Guid>("GuildId")
.HasColumnType("uuid");
b.Property<byte>("Rank")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("CharacterId");
b.HasIndex("GuildId");
b.ToTable("GuildMember");
});
modelBuilder.Entity("Server.DB.Documents.InventoryItem", b => modelBuilder.Entity("Server.DB.Documents.InventoryItem", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
@ -157,6 +203,12 @@ namespace Server.DB.Migrations
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired();
b.HasOne("Server.DB.Documents.Guild", "Guild")
.WithMany()
.HasForeignKey("GuildId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.OwnsOne("Wonderking.Packets.Outgoing.BaseStats", "BaseStats", b1 => b.OwnsOne("Wonderking.Packets.Outgoing.BaseStats", "BaseStats", b1 =>
{ {
b1.Property<Guid>("CharacterId") b1.Property<Guid>("CharacterId")
@ -217,9 +269,30 @@ namespace Server.DB.Migrations
b.Navigation("BaseStats"); b.Navigation("BaseStats");
b.Navigation("Guild");
b.Navigation("JobData"); b.Navigation("JobData");
}); });
modelBuilder.Entity("Server.DB.Documents.GuildMember", b =>
{
b.HasOne("Server.DB.Documents.Character", "Character")
.WithMany()
.HasForeignKey("CharacterId")
.OnDelete(DeleteBehavior.Cascade)
.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 => modelBuilder.Entity("Server.DB.Documents.InventoryItem", b =>
{ {
b.HasOne("Server.DB.Documents.Character", "Character") b.HasOne("Server.DB.Documents.Character", "Character")
@ -240,6 +313,11 @@ namespace Server.DB.Migrations
{ {
b.Navigation("InventoryItems"); b.Navigation("InventoryItems");
}); });
modelBuilder.Entity("Server.DB.Documents.Guild", b =>
{
b.Navigation("GuildMembers");
});
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }
} }

View file

@ -42,5 +42,10 @@ public class WonderkingContext : DbContext
.HasForeignKey(e => e.CharacterId).IsRequired(); .HasForeignKey(e => e.CharacterId).IsRequired();
builder.OwnsOne(p => p.BaseStats); builder.OwnsOne(p => p.BaseStats);
builder.OwnsOne(p => p.JobData); builder.OwnsOne(p => p.JobData);
}).Entity<InventoryItem>(builder => { builder.HasKey(i => i.Id); }); }).Entity<InventoryItem>(builder => { builder.HasKey(i => i.Id); }).Entity<Guild>(builder =>
{
builder.HasKey(g => g.Id);
builder.HasMany(g => g.GuildMembers).WithOne(g => g.Guild).HasForeignKey(g => g.GuildId)
.IsRequired();
});
} }

View file

@ -32,44 +32,48 @@ public class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPacket>
public Task HandleAsync(ChannelSelectionPacket packet, TcpSession session) public Task HandleAsync(ChannelSelectionPacket packet, TcpSession session)
{ {
var authSession = (AuthSession)session; var authSession = (AuthSession)session;
var charactersOfAccount = this._wonderkingContext.Accounts.Include(account => account.Characters)
.ThenInclude(character => character.InventoryItems).Include(account => account.Characters)
.ThenInclude(character => character.JobData).Include(account => account.Characters)
.ThenInclude(character => character.BaseStats)
.FirstOrDefault(a => a.Id == authSession.AccountId)
?.Characters;
ChannelSelectionResponsePacket responsePacket; ChannelSelectionResponsePacket responsePacket;
CharacterSelectionSetGuildNamePacket guildNameResponsePacket;
var testingChars = true; var hasCharacters = this._wonderkingContext.Accounts.Include(account => account.Characters)
if (charactersOfAccount != null && !testingChars) .FirstOrDefault(a => a.Id == authSession.AccountId)?.Characters.Count != 0;
var testingChars = false;
if (hasCharacters && !testingChars)
{ {
responsePacket = new ChannelSelectionResponsePacket responsePacket = new ChannelSelectionResponsePacket
{ {
ChannelIsFullFlag = 0, ChannelIsFullFlag = 0,
Endpoint = "127.0.0.1", Endpoint = "127.0.0.1",
Port = 12345, Port = 12345,
Characters = charactersOfAccount.Select((character, Characters = this._wonderkingContext.Characters.Where(c => c.AccountId == authSession.AccountId)
_) => new CharacterData .Select(c =>
new CharacterData
{ {
Name = character.Name, Name = c.Name,
Job = character.JobData, Job = c.JobData,
Gender = character.Gender, Gender = c.Gender,
Level = character.Level, Level = c.Level,
Experience = 0, Experience = 0,
Stats = character.BaseStats, Stats = c.BaseStats,
Health = character.Health, Health = c.Health,
Mana = character.Mana, Mana = c.Mana,
EquippedItems = EquippedItems =
character.InventoryItems.Where(item => item.ItemType == ItemType.WornEquipment) c.InventoryItems.Where(item => item.ItemType == ItemType.WornEquipment)
.Select(item => item.ItemId)
.ToArray(),
EquippedCashItems = c.InventoryItems
.Where(item => item.ItemType == ItemType.WornCashEquipment)
.Select(item => item.ItemId) .Select(item => item.ItemId)
.ToArray(), .ToArray(),
EquippedCashItems = character.InventoryItems
.Where(item => item.ItemType == ItemType.WornCashEquipment)
.Select(item => item.ItemId)
.ToArray(),
}) })
.ToArray(), .ToArray(),
}; };
guildNameResponsePacket = new CharacterSelectionSetGuildNamePacket
{
GuildNames = this._wonderkingContext.Characters.Where(c => c.AccountId == authSession.AccountId)
.Select(character => character.Guild.Name).ToArray()
};
} }
else else
{ {
@ -82,9 +86,18 @@ public class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPacket>
Port = 12345, Port = 12345,
Characters = Array.Empty<CharacterData>() Characters = Array.Empty<CharacterData>()
}; };
guildNameResponsePacket = new CharacterSelectionSetGuildNamePacket
{
GuildNames = new[] { "ABCDEFGHIJKLMNOP", "QRSTUVWXYZ123456", "A Guild Name For" }
};
} }
authSession.Send(responsePacket); authSession.Send(responsePacket);
if (guildNameResponsePacket.GuildNames.Length > 0)
{
authSession.Send(guildNameResponsePacket);
}
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -136,8 +149,8 @@ public class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPacket>
}, },
Health = int.MaxValue - 1, Health = int.MaxValue - 1,
Mana = int.MaxValue - 1, Mana = int.MaxValue - 1,
EquippedItems = Enumerable.Repeat((ushort)25, 20).ToArray(), EquippedItems = Enumerable.Repeat((ushort)35, 20).ToArray(),
EquippedCashItems = Enumerable.Repeat((ushort)70, 20).ToArray() EquippedCashItems = Enumerable.Repeat((ushort)55, 20).ToArray()
}, },
new CharacterData new CharacterData
{ {
@ -157,7 +170,7 @@ public class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPacket>
}, },
Health = int.MaxValue - 1, Health = int.MaxValue - 1,
Mana = int.MaxValue - 1, Mana = int.MaxValue - 1,
EquippedItems = Enumerable.Repeat((ushort)25, 20).ToArray(), EquippedItems = Enumerable.Repeat((ushort)45, 20).ToArray(),
EquippedCashItems = Enumerable.Repeat((ushort)65, 20).ToArray() EquippedCashItems = Enumerable.Repeat((ushort)65, 20).ToArray()
} }
}, },

View file

@ -5,5 +5,6 @@ public enum OperationCode : ushort
LoginInfo = 11, LoginInfo = 11,
LoginResponse = 12, LoginResponse = 12,
ChannelSelection = 13, ChannelSelection = 13,
ChannelSelectionResponse = 13 ChannelSelectionResponse = 13,
CharacterSelectionSetGuildName = 19,
} }

View file

@ -0,0 +1,5 @@
namespace Wonderking.Packets.Outgoing;
public struct CharacterGuildInfo
{
}

View file

@ -0,0 +1,30 @@
using System.Text;
namespace Wonderking.Packets.Outgoing;
[PacketId(OperationCode.CharacterSelectionSetGuildName)]
public class CharacterSelectionSetGuildNamePacket : IPacket
{
public required string[] GuildNames { get; set; }
public void Deserialize(byte[] data)
{
throw new NotSupportedException();
}
public byte[] Serialize()
{
Span<byte> data = stackalloc byte[1 + (16 + 1 + 1) * this.GuildNames.Length];
data.Clear();
data[0] = (byte)this.GuildNames.Length;
for (var i = 0; i < this.GuildNames.Length; i++)
{
data[1 + (i * (16 + 1 + 1))] = (byte)i;
Encoding.ASCII.GetBytes(this.GuildNames[i], data.Slice(2 + (i * (16 + 1 + 1)), 16));
// Null terminator
data[18 + (i * (16 + 1 + 1))] = 0;
}
return data.ToArray();
}
}