From e96ebfd33fca9b9b9a68f415dc3699fdc622460d Mon Sep 17 00:00:00 2001 From: rfi Date: Wed, 1 May 2024 16:11:11 +0700 Subject: [PATCH] sql server + items,character,tuts & echelons impl. --- .gitignore | 5 +- .../Crypto/TableEncryptionService.cs | 51 --- SCHALE.Common/Crypto/TableService.cs | 2 +- .../ModelExtensions/AccountExtensions.cs | 16 + .../Database/Models/AccountTutorial.cs | 12 + SCHALE.Common/Database/Models/GuestAccount.cs | 1 - SCHALE.Common/Database/SCHALEContext.cs | 100 ++--- SCHALE.Common/Database/ServicesExtesions.cs | 14 +- SCHALE.Common/Database/dbs.cs | 102 +++-- SCHALE.Common/FlatData/Form.cs | 12 +- .../FlatData/{MoveEndTable.cs => MoveEnd.cs} | 42 +- .../20240501053823_Init.Designer.cs | 189 +++++++++ .../Migrations/20240501053823_Init.cs | 124 ++++++ ...01071717_CharacterAndRelations.Designer.cs | 307 +++++++++++++++ .../20240501071717_CharacterAndRelations.cs | 104 +++++ .../20240501081158_UnMapIsNew.Designer.cs | 307 +++++++++++++++ .../Migrations/20240501081158_UnMapIsNew.cs | 29 ++ .../20240501090227_Echelons.Designer.cs | 368 ++++++++++++++++++ .../Migrations/20240501090227_Echelons.cs | 54 +++ .../Migrations/SCHALEContextModelSnapshot.cs | 365 +++++++++++++++++ SCHALE.Common/SCHALE.Common.csproj | 7 +- .../Api/ProtocolHandlers/Account.cs | 273 +++++++------ .../Controllers/Api/ProtocolHandlers/Item.cs | 7 +- .../Api/ProtocolHandlers/Mission.cs | 12 +- .../Api/ProtocolHandlers/Scenario.cs | 13 +- .../Controllers/Api/ProtocolHandlers/Shop.cs | 17 +- .../Controllers/UserController.cs | 4 +- SCHALE.GameServer/GameServer.cs | 18 +- .../Properties/launchSettings.json | 2 +- SCHALE.GameServer/SCHALE.GameServer.csproj | 4 + .../Services/ExcelTableService.cs | 55 +++ .../Services/SessionKeyService.cs | 9 +- SCHALE.GameServer/appsettings.json | 12 +- Scripts/migrate.ps1 | 40 ++ 34 files changed, 2330 insertions(+), 347 deletions(-) create mode 100644 SCHALE.Common/Database/ModelExtensions/AccountExtensions.cs create mode 100644 SCHALE.Common/Database/Models/AccountTutorial.cs rename SCHALE.Common/FlatData/{MoveEndTable.cs => MoveEnd.cs} (73%) create mode 100644 SCHALE.Common/Migrations/20240501053823_Init.Designer.cs create mode 100644 SCHALE.Common/Migrations/20240501053823_Init.cs create mode 100644 SCHALE.Common/Migrations/20240501071717_CharacterAndRelations.Designer.cs create mode 100644 SCHALE.Common/Migrations/20240501071717_CharacterAndRelations.cs create mode 100644 SCHALE.Common/Migrations/20240501081158_UnMapIsNew.Designer.cs create mode 100644 SCHALE.Common/Migrations/20240501081158_UnMapIsNew.cs create mode 100644 SCHALE.Common/Migrations/20240501090227_Echelons.Designer.cs create mode 100644 SCHALE.Common/Migrations/20240501090227_Echelons.cs create mode 100644 SCHALE.Common/Migrations/SCHALEContextModelSnapshot.cs create mode 100644 SCHALE.GameServer/Services/ExcelTableService.cs create mode 100644 Scripts/migrate.ps1 diff --git a/.gitignore b/.gitignore index 9491a2f..c974c4f 100644 --- a/.gitignore +++ b/.gitignore @@ -360,4 +360,7 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +FodyWeavers.xsd + +# EF migration +efbundle.exe \ No newline at end of file diff --git a/SCHALE.Common/Crypto/TableEncryptionService.cs b/SCHALE.Common/Crypto/TableEncryptionService.cs index 152a25a..b8ed59d 100644 --- a/SCHALE.Common/Crypto/TableEncryptionService.cs +++ b/SCHALE.Common/Crypto/TableEncryptionService.cs @@ -153,55 +153,4 @@ namespace SCHALE.Common.Crypto return Encoding.Unicode.GetString(strBytes); } } - - public static class FlatBuffersExtension - { - private static readonly Dictionary propertiesCache = []; - private static readonly Dictionary keyCache = []; - - /// - /// Only to be invoked by ExcelT, and only be invoked once per object. - /// - /// - /// - public static void Decode(this T table) where T : class - { - var type = table.GetType(); - PropertyInfo[] props; - - if (!propertiesCache.TryGetValue(type, out props!)) - { - props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); - propertiesCache.Add(type, props); - } - - foreach (var prop in props) - { - byte[] key; - if (!keyCache.TryGetValue(type, out key!)) - { - key = TableEncryptionService.CreateKey(type.Name.Replace("ExcelT", "")); - keyCache.Add(type, key); - } - - var baseType = prop.PropertyType.Name == "List`1" ? prop.PropertyType.GenericTypeArguments[0] : prop.PropertyType; - var convertMethod = TableEncryptionService.GetConvertMethod(baseType.IsEnum ? Enum.GetUnderlyingType(baseType) : baseType); - if (convertMethod is not null) - { - if (prop.PropertyType.Name == "List`1") - { - var list = (IList)prop.GetValue(table, null)!; - for (int i = 0; i < list.Count; i++) - { - list[i] = convertMethod.Invoke(null, [list[i], key]); - } - } - else - { - prop.SetValue(table, convertMethod.Invoke(null, [prop.GetValue(table, null), key])); - } - } - } - } - } } diff --git a/SCHALE.Common/Crypto/TableService.cs b/SCHALE.Common/Crypto/TableService.cs index e0d3dbe..f163d1a 100644 --- a/SCHALE.Common/Crypto/TableService.cs +++ b/SCHALE.Common/Crypto/TableService.cs @@ -40,7 +40,7 @@ namespace SCHALE.Common.Crypto { foreach (var type in Assembly.GetAssembly(typeof(AcademyFavorScheduleExcelTable))!.GetTypes().Where(t => t.IsAssignableTo(typeof(IFlatbufferObject)) && t.Name.EndsWith("ExcelTable"))) { - var bytesFilePath = Path.Join(bytesDir, $"{type.Name}.bytes"); + var bytesFilePath = Path.Join(bytesDir, $"{type.Name.ToLower()}.bytes"); if (!File.Exists(bytesFilePath)) { Console.WriteLine($"bytes files for {type.Name} not found. skipping..."); diff --git a/SCHALE.Common/Database/ModelExtensions/AccountExtensions.cs b/SCHALE.Common/Database/ModelExtensions/AccountExtensions.cs new file mode 100644 index 0000000..3175845 --- /dev/null +++ b/SCHALE.Common/Database/ModelExtensions/AccountExtensions.cs @@ -0,0 +1,16 @@ +namespace SCHALE.Common.Database.ModelExtensions +{ + public static class AccountExtensions + { + public static List AddCharacters(this AccountDB account, SCHALEContext context, params CharacterDB[] characters) + { + foreach (var character in characters) + { + character.AccountServerId = account.ServerId; + context.Characters.Add(character); + } + + return [.. characters]; + } + } +} diff --git a/SCHALE.Common/Database/Models/AccountTutorial.cs b/SCHALE.Common/Database/Models/AccountTutorial.cs new file mode 100644 index 0000000..f932908 --- /dev/null +++ b/SCHALE.Common/Database/Models/AccountTutorial.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace SCHALE.Common.Database.Models +{ + public class AccountTutorial + { + [Key] + public required long AccountServerId { get; set; } + + public List TutorialIds { get; set; } + } +} diff --git a/SCHALE.Common/Database/Models/GuestAccount.cs b/SCHALE.Common/Database/Models/GuestAccount.cs index 479a7c6..d02aab9 100644 --- a/SCHALE.Common/Database/Models/GuestAccount.cs +++ b/SCHALE.Common/Database/Models/GuestAccount.cs @@ -7,7 +7,6 @@ namespace SCHALE.Common.Database.Models public class GuestAccount { [Key] - [Column("_id")] public long Uid { get; set; } public string DeviceId { get; set; } diff --git a/SCHALE.Common/Database/SCHALEContext.cs b/SCHALE.Common/Database/SCHALEContext.cs index 92b680e..bd039f8 100644 --- a/SCHALE.Common/Database/SCHALEContext.cs +++ b/SCHALE.Common/Database/SCHALEContext.cs @@ -1,7 +1,7 @@ using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.ChangeTracking; -using Microsoft.EntityFrameworkCore.ValueGeneration; -using MongoDB.EntityFrameworkCore.Extensions; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Newtonsoft.Json; using SCHALE.Common.Database.Models; namespace SCHALE.Common.Database @@ -11,7 +11,15 @@ namespace SCHALE.Common.Database public DbSet GuestAccounts { get; set; } public DbSet Accounts { get; set; } public DbSet MissionProgresses { get; set; } - public DbSet Counters { get; set; } + public DbSet Items { get; set; } + public DbSet Characters { get; set; } + public DbSet Echelons { get; set; } + public DbSet AccountTutorials { get; set; } + + public static SCHALEContext Create(string connectionString) => + new(new DbContextOptionsBuilder() + .UseSqlServer(connectionString) + .Options); public SCHALEContext(DbContextOptions options) : base(options) { @@ -21,59 +29,53 @@ namespace SCHALE.Common.Database { base.OnModelCreating(modelBuilder); - modelBuilder.Entity().Property(x => x.Uid).HasValueGenerator(); - modelBuilder.Entity().ToCollection("guest_accounts"); + modelBuilder.Entity().Property(x => x.Uid).ValueGeneratedOnAdd(); - modelBuilder.Entity().Property(x => x.ServerId).HasValueGenerator(); - modelBuilder.Entity().ToCollection("accounts"); + modelBuilder.Entity().Property(x => x.ServerId).ValueGeneratedOnAdd(); + modelBuilder.Entity() + .HasMany(x => x.Items) + .WithOne(x => x.Account) + .HasForeignKey(x => x.AccountServerId) + .IsRequired(); + modelBuilder.Entity() + .HasMany(x => x.Characters) + .WithOne(x => x.Account) + .HasForeignKey(x => x.AccountServerId) + .IsRequired(); + modelBuilder.Entity() + .HasMany(x => x.MissionProgresses) + .WithOne(x => x.Account) + .HasForeignKey(x => x.AccountServerId) + .IsRequired(); - modelBuilder.Entity().Property(x => x.ServerId).HasValueGenerator(); - modelBuilder.Entity().ToCollection("mission_progresses"); + modelBuilder.Entity().Property(x => x.ServerId).ValueGeneratedOnAdd(); + modelBuilder.Entity().Property(x => x.ServerId).ValueGeneratedOnAdd(); - modelBuilder.Entity().ToCollection("counters"); + modelBuilder.Entity().Property(x => x.ServerId).ValueGeneratedOnAdd(); + modelBuilder.Entity().Property(x => x.EquipmentSlotAndDBIds).HasJsonConversion(); + modelBuilder.Entity().Property(x => x.PotentialStats).HasJsonConversion(); + + modelBuilder.Entity().Property(x => x.AccountServerId).ValueGeneratedNever(); + + modelBuilder.Entity().Property(x => x.ServerId).ValueGeneratedOnAdd(); + modelBuilder.Entity().Property(x => x.ProgressParameters).HasJsonConversion(); } + } - private class AccountAutoIncrementValueGenerator : AutoIncrementValueGenerator + public static class PropertyBuilderExtensions + { + public static PropertyBuilder HasJsonConversion(this PropertyBuilder propertyBuilder) where T : class, new() { - protected override string Collection => "account"; - } + ValueConverter converter = new + ( + v => JsonConvert.SerializeObject(v), + v => JsonConvert.DeserializeObject(v) ?? new T() + ); - private class GuestAccountAutoIncrementValueGenerator : AutoIncrementValueGenerator - { - protected override string Collection => "guest_account"; - } + propertyBuilder.HasConversion(converter); + propertyBuilder.Metadata.SetValueConverter(converter); - private class MissionProgressAutoIncrementValueGenerator : AutoIncrementValueGenerator - { - protected override string Collection => "mission_progress"; - } - - private abstract class AutoIncrementValueGenerator : ValueGenerator - { - protected abstract string Collection { get; } - public override bool GeneratesTemporaryValues => false; - - public override long Next(EntityEntry entry) - { - if (entry.Context is not SCHALEContext) - { - throw new ArgumentNullException($"{nameof(AutoIncrementValueGenerator)} is only implemented for {nameof(SCHALEContext)}"); - } - - var context = ((SCHALEContext)entry.Context); - var counter = context.Counters.SingleOrDefault(x => x.Id == Collection); - - if (counter is null) - { - counter = new Counter() { Id = Collection, Seq = 0 }; - context.Add(counter); - } - - counter.Seq++; - context.SaveChanges(); - - return counter.Seq; - } + return propertyBuilder; } } } diff --git a/SCHALE.Common/Database/ServicesExtesions.cs b/SCHALE.Common/Database/ServicesExtesions.cs index 3e7fe8f..bfe04f3 100644 --- a/SCHALE.Common/Database/ServicesExtesions.cs +++ b/SCHALE.Common/Database/ServicesExtesions.cs @@ -1,19 +1,19 @@ using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.ChangeTracking; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; namespace SCHALE.Common.Database { public static class ServicesExtesions { - public static void AddMongoDBProvider(this IServiceCollection services, string connectionString) + public static void AddSQLServerProvider(this IServiceCollection services, string connectionString) { - services.AddDbContext(opt => + services.AddDbContext(o => { - opt.UseMongoDB(connectionString, "SCHALE"); + o.UseSqlServer(connectionString, b => + { + b.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null); + }) + .UseLazyLoadingProxies(); }, ServiceLifetime.Singleton, ServiceLifetime.Singleton); } } diff --git a/SCHALE.Common/Database/dbs.cs b/SCHALE.Common/Database/dbs.cs index 0ce46d8..8589950 100644 --- a/SCHALE.Common/Database/dbs.cs +++ b/SCHALE.Common/Database/dbs.cs @@ -1,9 +1,9 @@ -using Newtonsoft.Json; using SCHALE.Common.FlatData; using SCHALE.Common.NetworkProtocol; using SCHALE.Common.Parcel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; namespace SCHALE.Common.Database { @@ -185,6 +185,18 @@ namespace SCHALE.Common.Database public class AccountDB { + [JsonIgnore] + public virtual ICollection Items { get; } + + [JsonIgnore] + public virtual ICollection Characters { get; } + + [JsonIgnore] + public virtual ICollection MissionProgresses { get; } + + [JsonIgnore] + public virtual ICollection Echelons { get; } + public AccountDB() { } public AccountDB(long publisherAccountId) @@ -197,14 +209,13 @@ namespace SCHALE.Common.Database } [Key] - [Column("_id")] public long ServerId { get; set; } - public string Nickname { get; set; } + public string? Nickname { get; set; } - public string CallName { get; set; } + public string? CallName { get; set; } - public string DevId { get; set; } + public string? DevId { get; set; } public AccountState State { get; set; } @@ -212,7 +223,7 @@ namespace SCHALE.Common.Database public long Exp { get; set; } - public string Comment { get; set; } + public string? Comment { get; set; } public int LobbyMode { get; set; } @@ -222,7 +233,7 @@ namespace SCHALE.Common.Database public DateTime LastConnectTime { get; set; } - public DateTime BirthDay { get; set; } + public DateTime? BirthDay { get; set; } public DateTime CallNameUpdateTime { get; set; } @@ -429,6 +440,8 @@ namespace SCHALE.Common.Database public int CafeRank { get; set; } public DateTime LastUpdate { get; set; } public DateTime? LastSummonDate { get; set; } + + [NotMapped] public bool IsNew { get; set; } public Dictionary CafeVisitCharacterDBs { get; set; } public List FurnitureDBs { get; set; } @@ -560,11 +573,20 @@ namespace SCHALE.Common.Database public class CharacterDB : ParcelBase { + [NotMapped] public override ParcelType Type { get => ParcelType.Character; } [JsonIgnore] + public virtual AccountDB Account { get; set; } + + [JsonIgnore] + public long AccountServerId { get; set; } + + [JsonIgnore] + [NotMapped] public override IEnumerable ParcelInfos { get; } + [Key] public long ServerId { get; set; } public long UniqueId { get; set; } public int StarGrade { get; set; } @@ -577,12 +599,14 @@ namespace SCHALE.Common.Database public int PassiveSkillLevel { get; set; } public int ExtraPassiveSkillLevel { get; set; } public int LeaderSkillLevel { get; set; } + + [NotMapped] public bool IsNew { get; set; } public bool IsLocked { get; set; } public bool IsFavorite { get; set; } - public List EquipmentServerIds { get; set; } - public Dictionary PotentialStats { get; set; } = new() { }; - public Dictionary EquipmentSlotAndDBIds { get; set; } + public List EquipmentServerIds { get; set; } = []; + public Dictionary PotentialStats { get; set; } = []; + public Dictionary EquipmentSlotAndDBIds { get; set; } = []; } @@ -831,12 +855,19 @@ namespace SCHALE.Common.Database public abstract class ConsumableItemBaseDB : ParcelBase { + [JsonIgnore] + public virtual AccountDB Account { get; set; } + [JsonIgnore] public abstract bool CanConsume { get; } [JsonIgnore] public ParcelKeyPair Key { get; } + [JsonIgnore] + public long AccountServerId { get; set; } + + [Key] public long ServerId { get; set; } public long UniqueId { get; set; } @@ -1002,22 +1033,23 @@ namespace SCHALE.Common.Database public class EchelonDB { + [Key] + [JsonIgnore] + public long ServerId { get; set; } + + [JsonIgnore] + public virtual AccountDB Account { get; set; } + public long AccountServerId { get; set; } public EchelonType EchelonType { get; set; } public long EchelonNumber { get; set; } public EchelonExtensionType ExtensionType { get; set; } public long LeaderServerId { get; set; } - public int MainSlotCount { get; set; } - public int SupportSlotCount { get; set; } - public List MainSlotServerIds { get; set; } - public List SupportSlotServerIds { get; set; } + public List MainSlotServerIds { get; set; } = []; + public List SupportSlotServerIds { get; set; } = []; public long TSSInteractionServerId { get; set; } public EchelonStatusFlag UsingFlag { get; set; } - public bool IsUsing { get; set; } - public List AllCharacterServerIds { get; set; } - public List AllCharacterWithoutTSSServerIds { get; set; } - public List BattleCharacterServerIds { get; set; } - public List SkillCardMulliganCharacterIds { get; set; } + public List SkillCardMulliganCharacterIds { get; set; } = []; } @@ -1088,6 +1120,8 @@ namespace SCHALE.Common.Database public long Exp { get; set; } public int Tier { get; set; } public long BoundCharacterServerId { get; set; } + + [NotMapped] public bool IsNew { get; set; } public bool IsLocked { get; set; } } @@ -1464,15 +1498,20 @@ namespace SCHALE.Common.Database public class ItemDB : ConsumableItemBaseDB { - public override ParcelType Type { get => ParcelType.Item; } + [NotMapped] + public override ParcelType Type => ParcelType.Item; + [NotMapped] [JsonIgnore] public override IEnumerable ParcelInfos { get; } + [NotMapped] [JsonIgnore] - public override bool CanConsume { get; } + public override bool CanConsume => true; + [NotMapped] public bool IsNew { get; set; } + public bool IsLocked { get; set; } } @@ -1566,32 +1605,19 @@ namespace SCHALE.Common.Database public class MissionProgressDB { [Key] - [Column("_id")] [JsonIgnore] public long ServerId { get; set; } + [JsonIgnore] + public virtual AccountDB Account { get; set; } + [JsonIgnore] public long AccountServerId { get; set; } public long MissionUniqueId { get; set; } public bool Complete { get; set; } public DateTime StartTime { get; set; } - - [JsonIgnore] - public string SerializedProgressParameters { get; private set; } = "{}"; - - [NotMapped] - public Dictionary ProgressParameters - { - get - { - return JsonConvert.DeserializeObject>(SerializedProgressParameters) ?? []; - } - set - { - SerializedProgressParameters = JsonConvert.SerializeObject(value); - } - } + public Dictionary ProgressParameters { get; set; } = []; } diff --git a/SCHALE.Common/FlatData/Form.cs b/SCHALE.Common/FlatData/Form.cs index c4642cd..a6219fd 100644 --- a/SCHALE.Common/FlatData/Form.cs +++ b/SCHALE.Common/FlatData/Form.cs @@ -20,11 +20,11 @@ public struct Form : IFlatbufferObject public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } public Form __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } - public SCHALE.Common.FlatData.MoveEndTable? MoveEnd { get { int o = __p.__offset(4); return o != 0 ? (SCHALE.Common.FlatData.MoveEndTable?)(new SCHALE.Common.FlatData.MoveEndTable()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } + public SCHALE.Common.FlatData.MoveEnd? MoveEnd { get { int o = __p.__offset(4); return o != 0 ? (SCHALE.Common.FlatData.MoveEnd?)(new SCHALE.Common.FlatData.MoveEnd()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } public SCHALE.Common.FlatData.Motion? PublicSkill { get { int o = __p.__offset(6); return o != 0 ? (SCHALE.Common.FlatData.Motion?)(new SCHALE.Common.FlatData.Motion()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } public static Offset CreateForm(FlatBufferBuilder builder, - Offset MoveEndOffset = default(Offset), + Offset MoveEndOffset = default(Offset), Offset PublicSkillOffset = default(Offset)) { builder.StartTable(2); Form.AddPublicSkill(builder, PublicSkillOffset); @@ -33,7 +33,7 @@ public struct Form : IFlatbufferObject } public static void StartForm(FlatBufferBuilder builder) { builder.StartTable(2); } - public static void AddMoveEnd(FlatBufferBuilder builder, Offset moveEndOffset) { builder.AddOffset(0, moveEndOffset.Value, 0); } + public static void AddMoveEnd(FlatBufferBuilder builder, Offset moveEndOffset) { builder.AddOffset(0, moveEndOffset.Value, 0); } public static void AddPublicSkill(FlatBufferBuilder builder, Offset publicSkillOffset) { builder.AddOffset(1, publicSkillOffset.Value, 0); } public static Offset EndForm(FlatBufferBuilder builder) { int o = builder.EndTable(); @@ -51,7 +51,7 @@ public struct Form : IFlatbufferObject } public static Offset Pack(FlatBufferBuilder builder, FormT _o) { if (_o == null) return default(Offset); - var _MoveEnd = _o.MoveEnd == null ? default(Offset) : SCHALE.Common.FlatData.MoveEndTable.Pack(builder, _o.MoveEnd); + var _MoveEnd = _o.MoveEnd == null ? default(Offset) : SCHALE.Common.FlatData.MoveEnd.Pack(builder, _o.MoveEnd); var _PublicSkill = _o.PublicSkill == null ? default(Offset) : SCHALE.Common.FlatData.Motion.Pack(builder, _o.PublicSkill); return CreateForm( builder, @@ -62,7 +62,7 @@ public struct Form : IFlatbufferObject public class FormT { - public SCHALE.Common.FlatData.MoveEndTableT MoveEnd { get; set; } + public SCHALE.Common.FlatData.MoveEndT MoveEnd { get; set; } public SCHALE.Common.FlatData.MotionT PublicSkill { get; set; } public FormT() { @@ -77,7 +77,7 @@ static public class FormVerify static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) { return verifier.VerifyTableStart(tablePos) - && verifier.VerifyTable(tablePos, 4 /*MoveEnd*/, SCHALE.Common.FlatData.MoveEndTableVerify.Verify, false) + && verifier.VerifyTable(tablePos, 4 /*MoveEnd*/, SCHALE.Common.FlatData.MoveEndVerify.Verify, false) && verifier.VerifyTable(tablePos, 6 /*PublicSkill*/, SCHALE.Common.FlatData.MotionVerify.Verify, false) && verifier.VerifyTableEnd(tablePos); } diff --git a/SCHALE.Common/FlatData/MoveEndTable.cs b/SCHALE.Common/FlatData/MoveEnd.cs similarity index 73% rename from SCHALE.Common/FlatData/MoveEndTable.cs rename to SCHALE.Common/FlatData/MoveEnd.cs index 466083f..ecafaae 100644 --- a/SCHALE.Common/FlatData/MoveEndTable.cs +++ b/SCHALE.Common/FlatData/MoveEnd.cs @@ -10,56 +10,56 @@ using global::System.Collections.Generic; using global::SCHALE.Common.Crypto; using global::Google.FlatBuffers; -public struct MoveEndTable : IFlatbufferObject +public struct MoveEnd : IFlatbufferObject { private Table __p; public ByteBuffer ByteBuffer { get { return __p.bb; } } public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_24_3_25(); } - public static MoveEndTable GetRootAsMoveEndTable(ByteBuffer _bb) { return GetRootAsMoveEndTable(_bb, new MoveEndTable()); } - public static MoveEndTable GetRootAsMoveEndTable(ByteBuffer _bb, MoveEndTable obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } + public static MoveEnd GetRootAsMoveEnd(ByteBuffer _bb) { return GetRootAsMoveEnd(_bb, new MoveEnd()); } + public static MoveEnd GetRootAsMoveEnd(ByteBuffer _bb, MoveEnd obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } - public MoveEndTable __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + public MoveEnd __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } public SCHALE.Common.FlatData.Motion? Normal { get { int o = __p.__offset(4); return o != 0 ? (SCHALE.Common.FlatData.Motion?)(new SCHALE.Common.FlatData.Motion()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } public SCHALE.Common.FlatData.Motion? Stand { get { int o = __p.__offset(6); return o != 0 ? (SCHALE.Common.FlatData.Motion?)(new SCHALE.Common.FlatData.Motion()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } public SCHALE.Common.FlatData.Motion? Kneel { get { int o = __p.__offset(8); return o != 0 ? (SCHALE.Common.FlatData.Motion?)(new SCHALE.Common.FlatData.Motion()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } } - public static Offset CreateMoveEndTable(FlatBufferBuilder builder, + public static Offset CreateMoveEnd(FlatBufferBuilder builder, Offset NormalOffset = default(Offset), Offset StandOffset = default(Offset), Offset KneelOffset = default(Offset)) { builder.StartTable(3); - MoveEndTable.AddKneel(builder, KneelOffset); - MoveEndTable.AddStand(builder, StandOffset); - MoveEndTable.AddNormal(builder, NormalOffset); - return MoveEndTable.EndMoveEndTable(builder); + MoveEnd.AddKneel(builder, KneelOffset); + MoveEnd.AddStand(builder, StandOffset); + MoveEnd.AddNormal(builder, NormalOffset); + return MoveEnd.EndMoveEnd(builder); } - public static void StartMoveEndTable(FlatBufferBuilder builder) { builder.StartTable(3); } + public static void StartMoveEnd(FlatBufferBuilder builder) { builder.StartTable(3); } public static void AddNormal(FlatBufferBuilder builder, Offset normalOffset) { builder.AddOffset(0, normalOffset.Value, 0); } public static void AddStand(FlatBufferBuilder builder, Offset standOffset) { builder.AddOffset(1, standOffset.Value, 0); } public static void AddKneel(FlatBufferBuilder builder, Offset kneelOffset) { builder.AddOffset(2, kneelOffset.Value, 0); } - public static Offset EndMoveEndTable(FlatBufferBuilder builder) { + public static Offset EndMoveEnd(FlatBufferBuilder builder) { int o = builder.EndTable(); - return new Offset(o); + return new Offset(o); } - public MoveEndTableT UnPack() { - var _o = new MoveEndTableT(); + public MoveEndT UnPack() { + var _o = new MoveEndT(); this.UnPackTo(_o); return _o; } - public void UnPackTo(MoveEndTableT _o) { + public void UnPackTo(MoveEndT _o) { byte[] key = { 0 }; _o.Normal = this.Normal.HasValue ? this.Normal.Value.UnPack() : null; _o.Stand = this.Stand.HasValue ? this.Stand.Value.UnPack() : null; _o.Kneel = this.Kneel.HasValue ? this.Kneel.Value.UnPack() : null; } - public static Offset Pack(FlatBufferBuilder builder, MoveEndTableT _o) { - if (_o == null) return default(Offset); + public static Offset Pack(FlatBufferBuilder builder, MoveEndT _o) { + if (_o == null) return default(Offset); var _Normal = _o.Normal == null ? default(Offset) : SCHALE.Common.FlatData.Motion.Pack(builder, _o.Normal); var _Stand = _o.Stand == null ? default(Offset) : SCHALE.Common.FlatData.Motion.Pack(builder, _o.Stand); var _Kneel = _o.Kneel == null ? default(Offset) : SCHALE.Common.FlatData.Motion.Pack(builder, _o.Kneel); - return CreateMoveEndTable( + return CreateMoveEnd( builder, _Normal, _Stand, @@ -67,13 +67,13 @@ public struct MoveEndTable : IFlatbufferObject } } -public class MoveEndTableT +public class MoveEndT { public SCHALE.Common.FlatData.MotionT Normal { get; set; } public SCHALE.Common.FlatData.MotionT Stand { get; set; } public SCHALE.Common.FlatData.MotionT Kneel { get; set; } - public MoveEndTableT() { + public MoveEndT() { this.Normal = null; this.Stand = null; this.Kneel = null; @@ -81,7 +81,7 @@ public class MoveEndTableT } -static public class MoveEndTableVerify +static public class MoveEndVerify { static public bool Verify(Google.FlatBuffers.Verifier verifier, uint tablePos) { diff --git a/SCHALE.Common/Migrations/20240501053823_Init.Designer.cs b/SCHALE.Common/Migrations/20240501053823_Init.Designer.cs new file mode 100644 index 0000000..e882550 --- /dev/null +++ b/SCHALE.Common/Migrations/20240501053823_Init.Designer.cs @@ -0,0 +1,189 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using SCHALE.Common.Database; + +#nullable disable + +namespace SCHALE.Common.Migrations +{ + [DbContext(typeof(SCHALEContext))] + [Migration("20240501053823_Init")] + partial class Init + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("SCHALE.Common.Database.AccountDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("BirthDay") + .HasColumnType("datetime2"); + + b.Property("CallName") + .HasColumnType("nvarchar(max)"); + + b.Property("CallNameUpdateTime") + .HasColumnType("datetime2"); + + b.Property("Comment") + .HasColumnType("nvarchar(max)"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("DevId") + .HasColumnType("nvarchar(max)"); + + b.Property("Exp") + .HasColumnType("bigint"); + + b.Property("LastConnectTime") + .HasColumnType("datetime2"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("LinkRewardDate") + .HasColumnType("datetime2"); + + b.Property("LobbyMode") + .HasColumnType("int"); + + b.Property("MemoryLobbyUniqueId") + .HasColumnType("bigint"); + + b.Property("Nickname") + .HasColumnType("nvarchar(max)"); + + b.Property("PublisherAccountId") + .HasColumnType("bigint"); + + b.Property("RepresentCharacterServerId") + .HasColumnType("int"); + + b.Property("RetentionDays") + .HasColumnType("int"); + + b.Property("State") + .HasColumnType("int"); + + b.Property("UnReadMailCount") + .HasColumnType("int"); + + b.Property("VIPLevel") + .HasColumnType("int"); + + b.HasKey("ServerId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.ItemDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("IsLocked") + .HasColumnType("bit"); + + b.Property("StackCount") + .HasColumnType("bigint"); + + b.Property("UniqueId") + .HasColumnType("bigint"); + + b.HasKey("ServerId"); + + b.ToTable("Items"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.MissionProgressDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("Complete") + .HasColumnType("bit"); + + b.Property("MissionUniqueId") + .HasColumnType("bigint"); + + b.Property("ProgressParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartTime") + .HasColumnType("datetime2"); + + b.HasKey("ServerId"); + + b.ToTable("MissionProgresses"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.Models.AccountTutorial", b => + { + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("TutorialIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("AccountServerId"); + + b.ToTable("AccountTutorials"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.Models.GuestAccount", b => + { + b.Property("Uid") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Uid")); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Token") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Uid"); + + b.ToTable("GuestAccounts"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SCHALE.Common/Migrations/20240501053823_Init.cs b/SCHALE.Common/Migrations/20240501053823_Init.cs new file mode 100644 index 0000000..d4892d1 --- /dev/null +++ b/SCHALE.Common/Migrations/20240501053823_Init.cs @@ -0,0 +1,124 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace SCHALE.Common.Migrations +{ + /// + public partial class Init : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Accounts", + columns: table => new + { + ServerId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Nickname = table.Column(type: "nvarchar(max)", nullable: true), + CallName = table.Column(type: "nvarchar(max)", nullable: true), + DevId = table.Column(type: "nvarchar(max)", nullable: true), + State = table.Column(type: "int", nullable: false), + Level = table.Column(type: "int", nullable: false), + Exp = table.Column(type: "bigint", nullable: false), + Comment = table.Column(type: "nvarchar(max)", nullable: true), + LobbyMode = table.Column(type: "int", nullable: false), + RepresentCharacterServerId = table.Column(type: "int", nullable: false), + MemoryLobbyUniqueId = table.Column(type: "bigint", nullable: false), + LastConnectTime = table.Column(type: "datetime2", nullable: false), + BirthDay = table.Column(type: "datetime2", nullable: true), + CallNameUpdateTime = table.Column(type: "datetime2", nullable: false), + PublisherAccountId = table.Column(type: "bigint", nullable: false), + RetentionDays = table.Column(type: "int", nullable: true), + VIPLevel = table.Column(type: "int", nullable: true), + CreateDate = table.Column(type: "datetime2", nullable: false), + UnReadMailCount = table.Column(type: "int", nullable: true), + LinkRewardDate = table.Column(type: "datetime2", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Accounts", x => x.ServerId); + }); + + migrationBuilder.CreateTable( + name: "AccountTutorials", + columns: table => new + { + AccountServerId = table.Column(type: "bigint", nullable: false), + TutorialIds = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AccountTutorials", x => x.AccountServerId); + }); + + migrationBuilder.CreateTable( + name: "GuestAccounts", + columns: table => new + { + Uid = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + DeviceId = table.Column(type: "nvarchar(max)", nullable: false), + Token = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_GuestAccounts", x => x.Uid); + }); + + migrationBuilder.CreateTable( + name: "Items", + columns: table => new + { + ServerId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + IsLocked = table.Column(type: "bit", nullable: false), + AccountServerId = table.Column(type: "bigint", nullable: false), + UniqueId = table.Column(type: "bigint", nullable: false), + StackCount = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Items", x => x.ServerId); + }); + + migrationBuilder.CreateTable( + name: "MissionProgresses", + columns: table => new + { + ServerId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + AccountServerId = table.Column(type: "bigint", nullable: false), + MissionUniqueId = table.Column(type: "bigint", nullable: false), + Complete = table.Column(type: "bit", nullable: false), + StartTime = table.Column(type: "datetime2", nullable: false), + ProgressParameters = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_MissionProgresses", x => x.ServerId); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Accounts"); + + migrationBuilder.DropTable( + name: "AccountTutorials"); + + migrationBuilder.DropTable( + name: "GuestAccounts"); + + migrationBuilder.DropTable( + name: "Items"); + + migrationBuilder.DropTable( + name: "MissionProgresses"); + } + } +} diff --git a/SCHALE.Common/Migrations/20240501071717_CharacterAndRelations.Designer.cs b/SCHALE.Common/Migrations/20240501071717_CharacterAndRelations.Designer.cs new file mode 100644 index 0000000..6743cb0 --- /dev/null +++ b/SCHALE.Common/Migrations/20240501071717_CharacterAndRelations.Designer.cs @@ -0,0 +1,307 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using SCHALE.Common.Database; + +#nullable disable + +namespace SCHALE.Common.Migrations +{ + [DbContext(typeof(SCHALEContext))] + [Migration("20240501071717_CharacterAndRelations")] + partial class CharacterAndRelations + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("SCHALE.Common.Database.AccountDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("BirthDay") + .HasColumnType("datetime2"); + + b.Property("CallName") + .HasColumnType("nvarchar(max)"); + + b.Property("CallNameUpdateTime") + .HasColumnType("datetime2"); + + b.Property("Comment") + .HasColumnType("nvarchar(max)"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("DevId") + .HasColumnType("nvarchar(max)"); + + b.Property("Exp") + .HasColumnType("bigint"); + + b.Property("LastConnectTime") + .HasColumnType("datetime2"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("LinkRewardDate") + .HasColumnType("datetime2"); + + b.Property("LobbyMode") + .HasColumnType("int"); + + b.Property("MemoryLobbyUniqueId") + .HasColumnType("bigint"); + + b.Property("Nickname") + .HasColumnType("nvarchar(max)"); + + b.Property("PublisherAccountId") + .HasColumnType("bigint"); + + b.Property("RepresentCharacterServerId") + .HasColumnType("int"); + + b.Property("RetentionDays") + .HasColumnType("int"); + + b.Property("State") + .HasColumnType("int"); + + b.Property("UnReadMailCount") + .HasColumnType("int"); + + b.Property("VIPLevel") + .HasColumnType("int"); + + b.HasKey("ServerId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.CharacterDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("EquipmentServerIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EquipmentSlotAndDBIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExSkillLevel") + .HasColumnType("int"); + + b.Property("Exp") + .HasColumnType("bigint"); + + b.Property("ExtraPassiveSkillLevel") + .HasColumnType("int"); + + b.Property("FavorExp") + .HasColumnType("bigint"); + + b.Property("FavorRank") + .HasColumnType("int"); + + b.Property("IsFavorite") + .HasColumnType("bit"); + + b.Property("IsLocked") + .HasColumnType("bit"); + + b.Property("IsNew") + .HasColumnType("bit"); + + b.Property("LeaderSkillLevel") + .HasColumnType("int"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("PassiveSkillLevel") + .HasColumnType("int"); + + b.Property("PotentialStats") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PublicSkillLevel") + .HasColumnType("int"); + + b.Property("StarGrade") + .HasColumnType("int"); + + b.Property("UniqueId") + .HasColumnType("bigint"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("Characters"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.ItemDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("IsLocked") + .HasColumnType("bit"); + + b.Property("StackCount") + .HasColumnType("bigint"); + + b.Property("UniqueId") + .HasColumnType("bigint"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("Items"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.MissionProgressDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("Complete") + .HasColumnType("bit"); + + b.Property("MissionUniqueId") + .HasColumnType("bigint"); + + b.Property("ProgressParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartTime") + .HasColumnType("datetime2"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("MissionProgresses"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.Models.AccountTutorial", b => + { + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("TutorialIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("AccountServerId"); + + b.ToTable("AccountTutorials"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.Models.GuestAccount", b => + { + b.Property("Uid") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Uid")); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Token") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Uid"); + + b.ToTable("GuestAccounts"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.CharacterDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("Characters") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.ItemDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("Items") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.MissionProgressDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("MissionProgresses") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.AccountDB", b => + { + b.Navigation("Characters"); + + b.Navigation("Items"); + + b.Navigation("MissionProgresses"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SCHALE.Common/Migrations/20240501071717_CharacterAndRelations.cs b/SCHALE.Common/Migrations/20240501071717_CharacterAndRelations.cs new file mode 100644 index 0000000..2951d03 --- /dev/null +++ b/SCHALE.Common/Migrations/20240501071717_CharacterAndRelations.cs @@ -0,0 +1,104 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace SCHALE.Common.Migrations +{ + /// + public partial class CharacterAndRelations : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Characters", + columns: table => new + { + ServerId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + AccountServerId = table.Column(type: "bigint", nullable: false), + UniqueId = table.Column(type: "bigint", nullable: false), + StarGrade = table.Column(type: "int", nullable: false), + Level = table.Column(type: "int", nullable: false), + Exp = table.Column(type: "bigint", nullable: false), + FavorRank = table.Column(type: "int", nullable: false), + FavorExp = table.Column(type: "bigint", nullable: false), + PublicSkillLevel = table.Column(type: "int", nullable: false), + ExSkillLevel = table.Column(type: "int", nullable: false), + PassiveSkillLevel = table.Column(type: "int", nullable: false), + ExtraPassiveSkillLevel = table.Column(type: "int", nullable: false), + LeaderSkillLevel = table.Column(type: "int", nullable: false), + IsNew = table.Column(type: "bit", nullable: false), + IsLocked = table.Column(type: "bit", nullable: false), + IsFavorite = table.Column(type: "bit", nullable: false), + EquipmentServerIds = table.Column(type: "nvarchar(max)", nullable: false), + PotentialStats = table.Column(type: "nvarchar(max)", nullable: false), + EquipmentSlotAndDBIds = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Characters", x => x.ServerId); + table.ForeignKey( + name: "FK_Characters_Accounts_AccountServerId", + column: x => x.AccountServerId, + principalTable: "Accounts", + principalColumn: "ServerId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_MissionProgresses_AccountServerId", + table: "MissionProgresses", + column: "AccountServerId"); + + migrationBuilder.CreateIndex( + name: "IX_Items_AccountServerId", + table: "Items", + column: "AccountServerId"); + + migrationBuilder.CreateIndex( + name: "IX_Characters_AccountServerId", + table: "Characters", + column: "AccountServerId"); + + migrationBuilder.AddForeignKey( + name: "FK_Items_Accounts_AccountServerId", + table: "Items", + column: "AccountServerId", + principalTable: "Accounts", + principalColumn: "ServerId", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_MissionProgresses_Accounts_AccountServerId", + table: "MissionProgresses", + column: "AccountServerId", + principalTable: "Accounts", + principalColumn: "ServerId", + onDelete: ReferentialAction.Cascade); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Items_Accounts_AccountServerId", + table: "Items"); + + migrationBuilder.DropForeignKey( + name: "FK_MissionProgresses_Accounts_AccountServerId", + table: "MissionProgresses"); + + migrationBuilder.DropTable( + name: "Characters"); + + migrationBuilder.DropIndex( + name: "IX_MissionProgresses_AccountServerId", + table: "MissionProgresses"); + + migrationBuilder.DropIndex( + name: "IX_Items_AccountServerId", + table: "Items"); + } + } +} diff --git a/SCHALE.Common/Migrations/20240501081158_UnMapIsNew.Designer.cs b/SCHALE.Common/Migrations/20240501081158_UnMapIsNew.Designer.cs new file mode 100644 index 0000000..7aecfbd --- /dev/null +++ b/SCHALE.Common/Migrations/20240501081158_UnMapIsNew.Designer.cs @@ -0,0 +1,307 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using SCHALE.Common.Database; + +#nullable disable + +namespace SCHALE.Common.Migrations +{ + [DbContext(typeof(SCHALEContext))] + [Migration("20240501081158_UnMapIsNew")] + partial class UnMapIsNew + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true) + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("SCHALE.Common.Database.AccountDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("BirthDay") + .HasColumnType("datetime2"); + + b.Property("CallName") + .HasColumnType("nvarchar(max)"); + + b.Property("CallNameUpdateTime") + .HasColumnType("datetime2"); + + b.Property("Comment") + .HasColumnType("nvarchar(max)"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("DevId") + .HasColumnType("nvarchar(max)"); + + b.Property("Exp") + .HasColumnType("bigint"); + + b.Property("LastConnectTime") + .HasColumnType("datetime2"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("LinkRewardDate") + .HasColumnType("datetime2"); + + b.Property("LobbyMode") + .HasColumnType("int"); + + b.Property("MemoryLobbyUniqueId") + .HasColumnType("bigint"); + + b.Property("Nickname") + .HasColumnType("nvarchar(max)"); + + b.Property("PublisherAccountId") + .HasColumnType("bigint"); + + b.Property("RepresentCharacterServerId") + .HasColumnType("int"); + + b.Property("RetentionDays") + .HasColumnType("int"); + + b.Property("State") + .HasColumnType("int"); + + b.Property("UnReadMailCount") + .HasColumnType("int"); + + b.Property("VIPLevel") + .HasColumnType("int"); + + b.HasKey("ServerId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.CharacterDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("EquipmentServerIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EquipmentSlotAndDBIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExSkillLevel") + .HasColumnType("int"); + + b.Property("Exp") + .HasColumnType("bigint"); + + b.Property("ExtraPassiveSkillLevel") + .HasColumnType("int"); + + b.Property("FavorExp") + .HasColumnType("bigint"); + + b.Property("FavorRank") + .HasColumnType("int"); + + b.Property("IsFavorite") + .HasColumnType("bit"); + + b.Property("IsLocked") + .HasColumnType("bit"); + + b.Property("LeaderSkillLevel") + .HasColumnType("int"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("PassiveSkillLevel") + .HasColumnType("int"); + + b.Property("PotentialStats") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PublicSkillLevel") + .HasColumnType("int"); + + b.Property("StarGrade") + .HasColumnType("int"); + + b.Property("UniqueId") + .HasColumnType("bigint"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("Characters"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.ItemDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("IsLocked") + .HasColumnType("bit"); + + b.Property("StackCount") + .HasColumnType("bigint"); + + b.Property("UniqueId") + .HasColumnType("bigint"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("Items"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.MissionProgressDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("Complete") + .HasColumnType("bit"); + + b.Property("MissionUniqueId") + .HasColumnType("bigint"); + + b.Property("ProgressParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartTime") + .HasColumnType("datetime2"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("MissionProgresses"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.Models.AccountTutorial", b => + { + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("TutorialIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("AccountServerId"); + + b.ToTable("AccountTutorials"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.Models.GuestAccount", b => + { + b.Property("Uid") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Uid")); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Token") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Uid"); + + b.ToTable("GuestAccounts"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.CharacterDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("Characters") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.ItemDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("Items") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.MissionProgressDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("MissionProgresses") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.AccountDB", b => + { + b.Navigation("Characters"); + + b.Navigation("Items"); + + b.Navigation("MissionProgresses"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SCHALE.Common/Migrations/20240501081158_UnMapIsNew.cs b/SCHALE.Common/Migrations/20240501081158_UnMapIsNew.cs new file mode 100644 index 0000000..9d0dc9c --- /dev/null +++ b/SCHALE.Common/Migrations/20240501081158_UnMapIsNew.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace SCHALE.Common.Migrations +{ + /// + public partial class UnMapIsNew : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsNew", + table: "Characters"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsNew", + table: "Characters", + type: "bit", + nullable: false, + defaultValue: false); + } + } +} diff --git a/SCHALE.Common/Migrations/20240501090227_Echelons.Designer.cs b/SCHALE.Common/Migrations/20240501090227_Echelons.Designer.cs new file mode 100644 index 0000000..b235b9d --- /dev/null +++ b/SCHALE.Common/Migrations/20240501090227_Echelons.Designer.cs @@ -0,0 +1,368 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using SCHALE.Common.Database; + +#nullable disable + +namespace SCHALE.Common.Migrations +{ + [DbContext(typeof(SCHALEContext))] + [Migration("20240501090227_Echelons")] + partial class Echelons + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true) + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("SCHALE.Common.Database.AccountDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("BirthDay") + .HasColumnType("datetime2"); + + b.Property("CallName") + .HasColumnType("nvarchar(max)"); + + b.Property("CallNameUpdateTime") + .HasColumnType("datetime2"); + + b.Property("Comment") + .HasColumnType("nvarchar(max)"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("DevId") + .HasColumnType("nvarchar(max)"); + + b.Property("Exp") + .HasColumnType("bigint"); + + b.Property("LastConnectTime") + .HasColumnType("datetime2"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("LinkRewardDate") + .HasColumnType("datetime2"); + + b.Property("LobbyMode") + .HasColumnType("int"); + + b.Property("MemoryLobbyUniqueId") + .HasColumnType("bigint"); + + b.Property("Nickname") + .HasColumnType("nvarchar(max)"); + + b.Property("PublisherAccountId") + .HasColumnType("bigint"); + + b.Property("RepresentCharacterServerId") + .HasColumnType("int"); + + b.Property("RetentionDays") + .HasColumnType("int"); + + b.Property("State") + .HasColumnType("int"); + + b.Property("UnReadMailCount") + .HasColumnType("int"); + + b.Property("VIPLevel") + .HasColumnType("int"); + + b.HasKey("ServerId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.CharacterDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("EquipmentServerIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EquipmentSlotAndDBIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExSkillLevel") + .HasColumnType("int"); + + b.Property("Exp") + .HasColumnType("bigint"); + + b.Property("ExtraPassiveSkillLevel") + .HasColumnType("int"); + + b.Property("FavorExp") + .HasColumnType("bigint"); + + b.Property("FavorRank") + .HasColumnType("int"); + + b.Property("IsFavorite") + .HasColumnType("bit"); + + b.Property("IsLocked") + .HasColumnType("bit"); + + b.Property("LeaderSkillLevel") + .HasColumnType("int"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("PassiveSkillLevel") + .HasColumnType("int"); + + b.Property("PotentialStats") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PublicSkillLevel") + .HasColumnType("int"); + + b.Property("StarGrade") + .HasColumnType("int"); + + b.Property("UniqueId") + .HasColumnType("bigint"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("Characters"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.EchelonDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("EchelonNumber") + .HasColumnType("bigint"); + + b.Property("EchelonType") + .HasColumnType("int"); + + b.Property("ExtensionType") + .HasColumnType("int"); + + b.Property("LeaderServerId") + .HasColumnType("bigint"); + + b.Property("MainSlotServerIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SkillCardMulliganCharacterIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportSlotServerIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TSSInteractionServerId") + .HasColumnType("bigint"); + + b.Property("UsingFlag") + .HasColumnType("int"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("Echelons"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.ItemDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("IsLocked") + .HasColumnType("bit"); + + b.Property("StackCount") + .HasColumnType("bigint"); + + b.Property("UniqueId") + .HasColumnType("bigint"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("Items"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.MissionProgressDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("Complete") + .HasColumnType("bit"); + + b.Property("MissionUniqueId") + .HasColumnType("bigint"); + + b.Property("ProgressParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartTime") + .HasColumnType("datetime2"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("MissionProgresses"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.Models.AccountTutorial", b => + { + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("TutorialIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("AccountServerId"); + + b.ToTable("AccountTutorials"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.Models.GuestAccount", b => + { + b.Property("Uid") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Uid")); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Token") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Uid"); + + b.ToTable("GuestAccounts"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.CharacterDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("Characters") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.EchelonDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("Echelons") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.ItemDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("Items") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.MissionProgressDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("MissionProgresses") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.AccountDB", b => + { + b.Navigation("Characters"); + + b.Navigation("Echelons"); + + b.Navigation("Items"); + + b.Navigation("MissionProgresses"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SCHALE.Common/Migrations/20240501090227_Echelons.cs b/SCHALE.Common/Migrations/20240501090227_Echelons.cs new file mode 100644 index 0000000..caf953b --- /dev/null +++ b/SCHALE.Common/Migrations/20240501090227_Echelons.cs @@ -0,0 +1,54 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace SCHALE.Common.Migrations +{ + /// + public partial class Echelons : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Echelons", + columns: table => new + { + ServerId = table.Column(type: "bigint", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + AccountServerId = table.Column(type: "bigint", nullable: false), + EchelonType = table.Column(type: "int", nullable: false), + EchelonNumber = table.Column(type: "bigint", nullable: false), + ExtensionType = table.Column(type: "int", nullable: false), + LeaderServerId = table.Column(type: "bigint", nullable: false), + MainSlotServerIds = table.Column(type: "nvarchar(max)", nullable: false), + SupportSlotServerIds = table.Column(type: "nvarchar(max)", nullable: false), + TSSInteractionServerId = table.Column(type: "bigint", nullable: false), + UsingFlag = table.Column(type: "int", nullable: false), + SkillCardMulliganCharacterIds = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Echelons", x => x.ServerId); + table.ForeignKey( + name: "FK_Echelons_Accounts_AccountServerId", + column: x => x.AccountServerId, + principalTable: "Accounts", + principalColumn: "ServerId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Echelons_AccountServerId", + table: "Echelons", + column: "AccountServerId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Echelons"); + } + } +} diff --git a/SCHALE.Common/Migrations/SCHALEContextModelSnapshot.cs b/SCHALE.Common/Migrations/SCHALEContextModelSnapshot.cs new file mode 100644 index 0000000..74f3825 --- /dev/null +++ b/SCHALE.Common/Migrations/SCHALEContextModelSnapshot.cs @@ -0,0 +1,365 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using SCHALE.Common.Database; + +#nullable disable + +namespace SCHALE.Common.Migrations +{ + [DbContext(typeof(SCHALEContext))] + partial class SCHALEContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true) + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("SCHALE.Common.Database.AccountDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("BirthDay") + .HasColumnType("datetime2"); + + b.Property("CallName") + .HasColumnType("nvarchar(max)"); + + b.Property("CallNameUpdateTime") + .HasColumnType("datetime2"); + + b.Property("Comment") + .HasColumnType("nvarchar(max)"); + + b.Property("CreateDate") + .HasColumnType("datetime2"); + + b.Property("DevId") + .HasColumnType("nvarchar(max)"); + + b.Property("Exp") + .HasColumnType("bigint"); + + b.Property("LastConnectTime") + .HasColumnType("datetime2"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("LinkRewardDate") + .HasColumnType("datetime2"); + + b.Property("LobbyMode") + .HasColumnType("int"); + + b.Property("MemoryLobbyUniqueId") + .HasColumnType("bigint"); + + b.Property("Nickname") + .HasColumnType("nvarchar(max)"); + + b.Property("PublisherAccountId") + .HasColumnType("bigint"); + + b.Property("RepresentCharacterServerId") + .HasColumnType("int"); + + b.Property("RetentionDays") + .HasColumnType("int"); + + b.Property("State") + .HasColumnType("int"); + + b.Property("UnReadMailCount") + .HasColumnType("int"); + + b.Property("VIPLevel") + .HasColumnType("int"); + + b.HasKey("ServerId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.CharacterDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("EquipmentServerIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EquipmentSlotAndDBIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ExSkillLevel") + .HasColumnType("int"); + + b.Property("Exp") + .HasColumnType("bigint"); + + b.Property("ExtraPassiveSkillLevel") + .HasColumnType("int"); + + b.Property("FavorExp") + .HasColumnType("bigint"); + + b.Property("FavorRank") + .HasColumnType("int"); + + b.Property("IsFavorite") + .HasColumnType("bit"); + + b.Property("IsLocked") + .HasColumnType("bit"); + + b.Property("LeaderSkillLevel") + .HasColumnType("int"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("PassiveSkillLevel") + .HasColumnType("int"); + + b.Property("PotentialStats") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("PublicSkillLevel") + .HasColumnType("int"); + + b.Property("StarGrade") + .HasColumnType("int"); + + b.Property("UniqueId") + .HasColumnType("bigint"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("Characters"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.EchelonDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("EchelonNumber") + .HasColumnType("bigint"); + + b.Property("EchelonType") + .HasColumnType("int"); + + b.Property("ExtensionType") + .HasColumnType("int"); + + b.Property("LeaderServerId") + .HasColumnType("bigint"); + + b.Property("MainSlotServerIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SkillCardMulliganCharacterIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("SupportSlotServerIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("TSSInteractionServerId") + .HasColumnType("bigint"); + + b.Property("UsingFlag") + .HasColumnType("int"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("Echelons"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.ItemDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("IsLocked") + .HasColumnType("bit"); + + b.Property("StackCount") + .HasColumnType("bigint"); + + b.Property("UniqueId") + .HasColumnType("bigint"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("Items"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.MissionProgressDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("Complete") + .HasColumnType("bit"); + + b.Property("MissionUniqueId") + .HasColumnType("bigint"); + + b.Property("ProgressParameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("StartTime") + .HasColumnType("datetime2"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("MissionProgresses"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.Models.AccountTutorial", b => + { + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("TutorialIds") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("AccountServerId"); + + b.ToTable("AccountTutorials"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.Models.GuestAccount", b => + { + b.Property("Uid") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Uid")); + + b.Property("DeviceId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Token") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Uid"); + + b.ToTable("GuestAccounts"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.CharacterDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("Characters") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.EchelonDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("Echelons") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.ItemDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("Items") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.MissionProgressDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("MissionProgresses") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.AccountDB", b => + { + b.Navigation("Characters"); + + b.Navigation("Echelons"); + + b.Navigation("Items"); + + b.Navigation("MissionProgresses"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SCHALE.Common/SCHALE.Common.csproj b/SCHALE.Common/SCHALE.Common.csproj index b441db4..05b2b83 100644 --- a/SCHALE.Common/SCHALE.Common.csproj +++ b/SCHALE.Common/SCHALE.Common.csproj @@ -9,7 +9,12 @@ - + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + diff --git a/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Account.cs b/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Account.cs index 07ef737..82c7587 100644 --- a/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Account.cs +++ b/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Account.cs @@ -1,21 +1,22 @@ using SCHALE.Common.Database; using SCHALE.Common.NetworkProtocol; using SCHALE.GameServer.Services; -using MongoDB.Driver.Linq; using SCHALE.Common.FlatData; -using Serilog; +using SCHALE.Common.Database.ModelExtensions; namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers { public class Account : ProtocolHandlerBase { - private ISessionKeyService sessionKeyService; - private SCHALEContext context; + private readonly ISessionKeyService sessionKeyService; + private readonly SCHALEContext context; + private readonly ExcelTableService excelTableService; - public Account(IProtocolHandlerFactory protocolHandlerFactory, ISessionKeyService _sessionKeyService, SCHALEContext _context) : base(protocolHandlerFactory) + public Account(IProtocolHandlerFactory protocolHandlerFactory, ISessionKeyService _sessionKeyService, SCHALEContext _context, ExcelTableService _excelTableService) : base(protocolHandlerFactory) { sessionKeyService = _sessionKeyService; context = _context; + excelTableService = _excelTableService; } // most handlers empty @@ -60,7 +61,59 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers { CurrentVersion = req.Version, AccountDB = account, - + StaticOpenConditions = new() + { + { OpenConditionContent.Shop, OpenConditionLockReason.None }, + { OpenConditionContent.Gacha, OpenConditionLockReason.None }, + { OpenConditionContent.LobbyIllust, OpenConditionLockReason.None }, + { OpenConditionContent.Raid, OpenConditionLockReason.StageClear }, + { OpenConditionContent.Cafe, OpenConditionLockReason.StageClear }, + { OpenConditionContent.Unit_Growth_Skill, OpenConditionLockReason.None }, + { OpenConditionContent.Unit_Growth_LevelUp, OpenConditionLockReason.None }, + { OpenConditionContent.Unit_Growth_Transcendence, OpenConditionLockReason.None }, + { OpenConditionContent.WeekDungeon, OpenConditionLockReason.StageClear }, + { OpenConditionContent.Arena, OpenConditionLockReason.StageClear }, + { OpenConditionContent.Academy, OpenConditionLockReason.StageClear }, + { OpenConditionContent.Equip, OpenConditionLockReason.None }, + { OpenConditionContent.Item, OpenConditionLockReason.None }, + { OpenConditionContent.Mission, OpenConditionLockReason.None }, + { OpenConditionContent.WeekDungeon_Chase, OpenConditionLockReason.StageClear }, + { OpenConditionContent.__Deprecated_WeekDungeon_FindGift, OpenConditionLockReason.None }, + { OpenConditionContent.__Deprecated_WeekDungeon_Blood, OpenConditionLockReason.None }, + { OpenConditionContent.Story_Sub, OpenConditionLockReason.None }, + { OpenConditionContent.Story_Replay, OpenConditionLockReason.None }, + { OpenConditionContent.None, OpenConditionLockReason.None }, + { OpenConditionContent.Shop_Gem, OpenConditionLockReason.None }, + { OpenConditionContent.Craft, OpenConditionLockReason.StageClear }, + { OpenConditionContent.Student, OpenConditionLockReason.None }, + { OpenConditionContent.GuideMission, OpenConditionLockReason.None }, + { OpenConditionContent.Clan, OpenConditionLockReason.StageClear }, + { OpenConditionContent.Echelon, OpenConditionLockReason.None }, + { OpenConditionContent.Campaign, OpenConditionLockReason.None }, + { OpenConditionContent.EventContent, OpenConditionLockReason.None }, + { OpenConditionContent.EventStage_1, OpenConditionLockReason.StageClear }, + { OpenConditionContent.EventStage_2, OpenConditionLockReason.None }, + { OpenConditionContent.Talk, OpenConditionLockReason.None }, + { OpenConditionContent.Billing, OpenConditionLockReason.None }, + { OpenConditionContent.Schedule, OpenConditionLockReason.None }, + { OpenConditionContent.Story, OpenConditionLockReason.None }, + { OpenConditionContent.Tactic_Speed, OpenConditionLockReason.StageClear }, + { OpenConditionContent.Cafe_Invite, OpenConditionLockReason.StageClear }, + { OpenConditionContent.Cafe_Invite_2, OpenConditionLockReason.CafeRank | OpenConditionLockReason.StageClear }, + { OpenConditionContent.EventMiniGame_1, OpenConditionLockReason.StageClear }, + { OpenConditionContent.SchoolDungeon, OpenConditionLockReason.StageClear }, + { OpenConditionContent.TimeAttackDungeon, OpenConditionLockReason.StageClear }, + { OpenConditionContent.ShiftingCraft, OpenConditionLockReason.StageClear }, + { OpenConditionContent.Tactic_Skip, OpenConditionLockReason.StageClear }, + { OpenConditionContent.Mulligan, OpenConditionLockReason.StageClear }, + { OpenConditionContent.EventPermanent, OpenConditionLockReason.StageClear }, + { OpenConditionContent.Main_L_1_2, OpenConditionLockReason.ScenarioModeClear }, + { OpenConditionContent.Main_L_1_3, OpenConditionLockReason.ScenarioModeClear }, + { OpenConditionContent.Main_L_1_4, OpenConditionLockReason.ScenarioModeClear }, + { OpenConditionContent.EliminateRaid, OpenConditionLockReason.StageClear }, + { OpenConditionContent.Cafe_2, OpenConditionLockReason.StageClear }, + { OpenConditionContent.MultiFloorRaid, OpenConditionLockReason.StageClear } + }, MissionProgressDBs = [.. context.MissionProgresses.Where(x => x.AccountServerId == account.ServerId)] }; @@ -84,6 +137,58 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers context.Accounts.Add(account); context.SaveChanges(); + // Default items + context.Items.Add(new() + { + AccountServerId = account.ServerId, + UniqueId = 2, + StackCount = 5 + }); + + // Default chars + var defaultCharacters = excelTableService.GetTable().UnPack().DataList; + var newCharacters = defaultCharacters.Select(x => + { + var characterExcel = excelTableService.GetTable().UnPack().DataList.Find(y => y.Id == x.CharacterId); + + return new CharacterDB() + { + UniqueId = x.CharacterId, + StarGrade = x.StarGrade, + Level = x.Level, + Exp = x.Exp, + FavorRank = x.FavorRank, + FavorExp = x.FavorExp, + PublicSkillLevel = 1, + ExSkillLevel = x.ExSkillLevel, + PassiveSkillLevel = x.PassiveSkillLevel, + ExtraPassiveSkillLevel = x.ExtraPassiveSkillLevel, + LeaderSkillLevel = x.LeaderSkillLevel, + IsNew = true, + IsLocked = true, + EquipmentServerIds = characterExcel is not null ? characterExcel.EquipmentSlot.Select(x => (long)0).ToList() : [0, 0, 0], + PotentialStats = { { 1, 0 }, { 2, 0 }, { 3, 0 } } + }; + }).ToList(); + account.AddCharacters(context, [.. newCharacters]); + context.SaveChanges(); + + var favCharacter = defaultCharacters.Find(x => x.FavoriteCharacter); + if (favCharacter is not null) + { + account.RepresentCharacterServerId = (int)newCharacters.First(x => x.UniqueId == favCharacter.CharacterId).ServerId; + } + if (newCharacters.Count > 0) + { + context.Echelons.Add(new() + { + AccountServerId = account.ServerId, + LeaderServerId = newCharacters[0].ServerId, + MainSlotServerIds = newCharacters.Take(3).Select(x => x.ServerId).Append(0).ToList() + }); + } + context.SaveChanges(); + return new AccountCreateResponse() { SessionKey = sessionKeyService.Create(account.PublisherAccountId) @@ -93,7 +198,7 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers [ProtocolHandler(Protocol.Account_Nickname)] public ResponsePacket NicknameHandler(AccountNicknameRequest req) { - var account = sessionKeyService.GetAccount(req.SessionKey!); + var account = sessionKeyService.GetAccount(req.SessionKey); account.Nickname = req.Nickname; context.SaveChanges(); @@ -108,6 +213,8 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers [ProtocolHandler(Protocol.Account_LoginSync)] public ResponsePacket LoginSyncHandler(AccountLoginSyncRequest req) { + var account = sessionKeyService.GetAccount(req.SessionKey); + return new AccountLoginSyncResponse() { AccountCurrencySyncResponse = new AccountCurrencySyncResponse() @@ -172,77 +279,7 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers }, CharacterListResponse = new CharacterListResponse() { - CharacterDBs = new List - { - new CharacterDB - { - ServerId = 1043998219, - UniqueId = 13003, - StarGrade = 2, - Level = 1, - FavorRank = 1, - PublicSkillLevel = 1, - ExSkillLevel = 1, - PassiveSkillLevel = 1, - ExtraPassiveSkillLevel = 1, - LeaderSkillLevel = 1, - IsNew = true, - IsLocked = true, - EquipmentServerIds = new List { 0, 0, 0 }, - PotentialStats = new Dictionary { { 1, 0 }, { 2, 0 }, { 3, 0 } } - }, - new CharacterDB - { - ServerId = 1043998217, - UniqueId = 13010, - StarGrade = 2, - Level = 1, - FavorRank = 1, - PublicSkillLevel = 1, - ExSkillLevel = 1, - PassiveSkillLevel = 1, - ExtraPassiveSkillLevel = 1, - LeaderSkillLevel = 1, - IsNew = true, - IsLocked = true, - EquipmentServerIds = new List { 0, 0, 0 }, - PotentialStats = new Dictionary { { 1, 0 }, { 2, 0 }, { 3, 0 } } - }, - new CharacterDB - { - ServerId = 1043998218, - UniqueId = 16003, - StarGrade = 1, - Level = 1, - FavorRank = 1, - PublicSkillLevel = 1, - ExSkillLevel = 1, - PassiveSkillLevel = 1, - ExtraPassiveSkillLevel = 1, - LeaderSkillLevel = 1, - IsNew = true, - IsLocked = true, - EquipmentServerIds = new List { 0, 0, 0 }, - PotentialStats = new Dictionary { { 1, 0 }, { 2, 0 }, { 3, 0 } } - }, - new CharacterDB - { - ServerId = 1043998220, - UniqueId = 26000, - StarGrade = 1, - Level = 1, - FavorRank = 1, - PublicSkillLevel = 1, - ExSkillLevel = 1, - PassiveSkillLevel = 1, - ExtraPassiveSkillLevel = 1, - LeaderSkillLevel = 1, - IsNew = true, - IsLocked = true, - EquipmentServerIds = new List { 0, 0, 0 }, - PotentialStats = new Dictionary { { 1, 0 }, { 2, 0 }, { 3, 0 } } - } - }, + CharacterDBs = [.. account.Characters], TSSCharacterDBs = [], WeaponDBs = [], CostumeDBs = [], @@ -255,8 +292,8 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers AccountServerId = req.AccountId, EchelonType = EchelonType.Adventure, EchelonNumber = 1, - LeaderServerId = 123, - MainSlotServerIds = [1043998217, 1043998218, 1043998219, 0 ], + LeaderServerId = 1, + MainSlotServerIds = [1, 2, 3, 0 ], SupportSlotServerIds = [ 444, 0], SkillCardMulliganCharacterIds = [] } @@ -280,48 +317,51 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers new() { EventContentId = 900701 }, ], }, - - FriendCode = "SCHALEPS", - - ServerNotification = ServerNotificationFlag.HasUnreadMail, - SessionKey = new() - { - AccountServerId = req.AccountId, - MxToken = req.SessionKey.MxToken, - }, + FriendCode = "SCHALE" }; } [ProtocolHandler(Protocol.Account_GetTutorial)] public ResponsePacket GetTutorialHandler(AccountGetTutorialRequest req) { + var tutorialIds = context.AccountTutorials.SingleOrDefault(x => x.AccountServerId == sessionKeyService.GetAccount(req.SessionKey).ServerId)?.TutorialIds; + return new AccountGetTutorialResponse() { -#if DEBUG - TutorialIds = [1, 2] -#endif + TutorialIds = tutorialIds ?? [] }; } [ProtocolHandler(Protocol.Account_SetTutorial)] public ResponsePacket SetTutorialHandler(AccountSetTutorialRequest req) { - - return new AccountSetTutorialResponse() + var account = sessionKeyService.GetAccount(req.SessionKey); + var tutorial = context.AccountTutorials.SingleOrDefault(x => x.AccountServerId == account.ServerId); + if (tutorial == null) { + tutorial = new() + { + AccountServerId = account.ServerId, + TutorialIds = req.TutorialIds + }; + context.AccountTutorials.Add(tutorial); + } + else + { + tutorial.TutorialIds = req.TutorialIds; + } + context.SaveChanges(); - }; + return new AccountSetTutorialResponse(); } - // others handlers, move to different handler group later + // TODO: others handlers, move to different handler group later [ProtocolHandler(Protocol.NetworkTime_Sync)] public ResponsePacket NetworkTime_SyncHandler(NetworkTimeSyncRequest req) { - long received_tick = DateTimeOffset.Now.Ticks; - return new NetworkTimeSyncResponse() { - ReceiveTick = received_tick, + ReceiveTick = DateTimeOffset.Now.Ticks, EchoSendTick = DateTimeOffset.Now.Ticks }; } @@ -329,70 +369,49 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers [ProtocolHandler(Protocol.ContentSave_Get)] public ResponsePacket ContentSave_GetHandler(ContentSaveGetRequest req) { - return new ContentSaveGetResponse() - { - ServerNotification = ServerNotificationFlag.HasUnreadMail, - }; + return new ContentSaveGetResponse(); } [ProtocolHandler(Protocol.Toast_List)] public ResponsePacket ToastListHandler(ToastListRequest req) { - return new ToastListResponse() - { - - }; + return new ToastListResponse(); } [ProtocolHandler(Protocol.ContentLog_UIOpenStatistics)] public ResponsePacket ContentLog_UIOpenStatisticsHandler(ContentLogUIOpenStatisticsRequest req) { - return new ContentLogUIOpenStatisticsResponse() - { - - }; + return new ContentLogUIOpenStatisticsResponse(); } [ProtocolHandler(Protocol.Event_RewardIncrease)] public ResponsePacket Event_RewardIncreaseHandler(EventRewardIncreaseRequest req) { - return new EventRewardIncreaseResponse() - { - - }; + return new EventRewardIncreaseResponse(); } [ProtocolHandler(Protocol.OpenCondition_EventList)] public ResponsePacket OpenCondition_EventListHandler(OpenConditionEventListRequest req) { - return new OpenConditionEventListResponse() - { - - }; + return new OpenConditionEventListResponse(); } [ProtocolHandler(Protocol.Notification_EventContentReddotCheck)] public ResponsePacket Notification_EventContentReddotCheckHandler(NotificationEventContentReddotRequest req) { - return new NotificationEventContentReddotResponse() - { - - }; + return new NotificationEventContentReddotResponse(); } [ProtocolHandler(Protocol.Billing_PurchaseListByYostar)] public ResponsePacket Billing_PurchaseListByYostarHandler(BillingPurchaseListByYostarRequest req) { - return new BillingPurchaseListByYostarResponse() - { - - }; + return new BillingPurchaseListByYostarResponse(); } } diff --git a/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Item.cs b/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Item.cs index fb590be..c045f58 100644 --- a/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Item.cs +++ b/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Item.cs @@ -18,11 +18,12 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers [ProtocolHandler(Protocol.Item_List)] public ResponsePacket ListHandler(ItemListRequest req) { + var account = sessionKeyService.GetAccount(req.SessionKey); + return new ItemListResponse() { - ItemDBs = [], - ExpiryItemDBs = [], - ServerNotification = ServerNotificationFlag.HasUnreadMail, + ItemDBs = [.. account.Items], + ExpiryItemDBs = [] }; } } diff --git a/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Mission.cs b/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Mission.cs index 61fdeb0..80e2b41 100644 --- a/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Mission.cs +++ b/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Mission.cs @@ -1,5 +1,4 @@ -using MongoDB.Driver.Linq; -using SCHALE.Common.Database; +using SCHALE.Common.Database; using SCHALE.Common.NetworkProtocol; using SCHALE.GameServer.Services; using Serilog; @@ -8,8 +7,8 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers { public class Mission : ProtocolHandlerBase { - private ISessionKeyService sessionKeyService; - private SCHALEContext context; + private readonly ISessionKeyService sessionKeyService; + private readonly SCHALEContext context; public Mission(IProtocolHandlerFactory protocolHandlerFactory, ISessionKeyService _sessionKeyService, SCHALEContext _context) : base(protocolHandlerFactory) { @@ -33,10 +32,7 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers [ProtocolHandler(Protocol.Mission_GuideMissionSeasonList)] public ResponsePacket GuideMissionSeasonListHandler(GuideMissionSeasonListRequest req) { - return new GuideMissionSeasonListResponse() - { - - }; + return new GuideMissionSeasonListResponse(); } } } diff --git a/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Scenario.cs b/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Scenario.cs index 1d3c20c..21afbc3 100644 --- a/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Scenario.cs +++ b/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Scenario.cs @@ -14,22 +14,13 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers Log.Information($"ScenarioSkipRequest SkipPointScriptCount: " + req.SkipPointScriptCount); // skip story doesn't work yet, probably need to implement missiondb - return new ScenarioSkipResponse() - { - - }; + return new ScenarioSkipResponse(); } [ProtocolHandler(Protocol.Scenario_Select)] public ResponsePacket SelectHandler(ScenarioSelectRequest req) { - - return new ScenarioSelectResponse() - { - - }; + return new ScenarioSelectResponse(); } - - } } diff --git a/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Shop.cs b/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Shop.cs index 5cc8d84..f820bc9 100644 --- a/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Shop.cs +++ b/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Shop.cs @@ -1,16 +1,16 @@ using SCHALE.Common.Database; using SCHALE.Common.NetworkProtocol; using SCHALE.GameServer.Services; -using Serilog; namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers { public class Shop : ProtocolHandlerBase { - private ISessionKeyService sessionKeyService; - private SCHALEContext context; + private readonly ISessionKeyService sessionKeyService; + private readonly SCHALEContext context; - public List SavedGachaResults { get; set; } // temp storage until gacha management + // TODO: temp storage until gacha management + public List SavedGachaResults { get; set; } = []; public Shop(IProtocolHandlerFactory protocolHandlerFactory, ISessionKeyService _sessionKeyService, SCHALEContext _context) : base(protocolHandlerFactory) { @@ -21,14 +21,7 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers [ProtocolHandler(Protocol.Shop_BeforehandGachaGet)] public ResponsePacket BeforehandGachaGetHandler(ShopBeforehandGachaGetRequest req) { - return new ShopBeforehandGachaGetResponse() - { - SessionKey = new() - { - MxToken = req.SessionKey.MxToken, - AccountServerId = req.SessionKey.AccountServerId, - } - }; + return new ShopBeforehandGachaGetResponse(); } [ProtocolHandler(Protocol.Shop_BeforehandGachaRun)] diff --git a/SCHALE.GameServer/Controllers/UserController.cs b/SCHALE.GameServer/Controllers/UserController.cs index c867b68..61d086b 100644 --- a/SCHALE.GameServer/Controllers/UserController.cs +++ b/SCHALE.GameServer/Controllers/UserController.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Mvc; using SCHALE.Common.Database; -using SCHALE.Common.Database.Models; using SCHALE.GameServer.Models; namespace SCHALE.GameServer.Controllers @@ -35,8 +34,9 @@ namespace SCHALE.GameServer.Controllers if (account is null) { account = new() { DeviceId = deviceId, Token = Guid.NewGuid().ToString() }; - context.Add(account); + context.GuestAccounts.Add(account); context.SaveChanges(); + rsp.IsNew = 1; } diff --git a/SCHALE.GameServer/GameServer.cs b/SCHALE.GameServer/GameServer.cs index e5ac829..bb3af75 100644 --- a/SCHALE.GameServer/GameServer.cs +++ b/SCHALE.GameServer/GameServer.cs @@ -5,6 +5,7 @@ using System.Reflection; using SCHALE.Common.Database; using SCHALE.GameServer.Controllers.Api.ProtocolHandlers; using SCHALE.GameServer.Services; +using Microsoft.EntityFrameworkCore; namespace SCHALE.GameServer { @@ -13,13 +14,15 @@ namespace SCHALE.GameServer public static void Main(string[] args) { var config = new ConfigurationBuilder() - .SetBasePath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!) + .SetBasePath(Path.GetDirectoryName(AppContext.BaseDirectory)!) .AddJsonFile("appsettings.json") + .AddJsonFile("appsettings.Local.json", true) .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", true) .Build(); { - var logFilePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "logs", "log.txt"); + var logFilePath = Path.Combine(Path.GetDirectoryName(AppContext.BaseDirectory)!, "logs", "log.txt"); + if (File.Exists(logFilePath)) { var prevLogFilePath = Path.Combine(Path.GetDirectoryName(logFilePath)!, "log-prev.txt"); @@ -28,6 +31,7 @@ namespace SCHALE.GameServer File.Move(logFilePath, prevLogFilePath); } + Log.Logger = new LoggerConfiguration() .WriteTo.Console() .WriteTo.File(logFilePath, restrictedToMinimumLevel: LogEventLevel.Verbose, shared: true) @@ -44,10 +48,11 @@ namespace SCHALE.GameServer builder.Host.UseSerilog(); // Add services to the container. + builder.Services.AddSQLServerProvider(config.GetConnectionString("SQLServer") ?? throw new ArgumentNullException("ConnectionStrings/SQLServer in appsettings is missing")); builder.Services.AddControllers(); - builder.Services.AddMongoDBProvider(config.GetConnectionString("MongoDB") ?? throw new ArgumentNullException("ConnectionStrings/MongoDB in appsettings is missing")); builder.Services.AddProtocolHandlerFactory(); builder.Services.AddMemorySessionKeyService(); + builder.Services.AddExcelTableService(); // Add all Handler Groups var handlerGroups = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsSubclassOf(typeof(ProtocolHandlerBase))); @@ -57,6 +62,13 @@ namespace SCHALE.GameServer var app = builder.Build(); + using (var scope = app.Services.CreateScope()) + { + var context = scope.ServiceProvider.GetRequiredService(); + if (context.Database.GetPendingMigrations().Any()) + context.Database.Migrate(); + } + // Configure the HTTP request pipeline. app.UseAuthorization(); app.UseSerilogRequestLogging(); diff --git a/SCHALE.GameServer/Properties/launchSettings.json b/SCHALE.GameServer/Properties/launchSettings.json index ec45758..05d1176 100644 --- a/SCHALE.GameServer/Properties/launchSettings.json +++ b/SCHALE.GameServer/Properties/launchSettings.json @@ -5,7 +5,7 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": false, - "applicationUrl": "https://0.0.0.0:443;http://0.0.0.0:80", + "externalUrlConfiguration": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/SCHALE.GameServer/SCHALE.GameServer.csproj b/SCHALE.GameServer/SCHALE.GameServer.csproj index 02a1e1e..8fd2e70 100644 --- a/SCHALE.GameServer/SCHALE.GameServer.csproj +++ b/SCHALE.GameServer/SCHALE.GameServer.csproj @@ -7,6 +7,10 @@ + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/SCHALE.GameServer/Services/ExcelTableService.cs b/SCHALE.GameServer/Services/ExcelTableService.cs new file mode 100644 index 0000000..af728f8 --- /dev/null +++ b/SCHALE.GameServer/Services/ExcelTableService.cs @@ -0,0 +1,55 @@ +using Google.FlatBuffers; +using SCHALE.Common.Crypto; +using System.Reflection; + +namespace SCHALE.GameServer.Services +{ + // TODO: High priority, cache UnPack-ed table! + public class ExcelTableService + { + private readonly ILogger logger; + private readonly Dictionary caches = []; + + public ExcelTableService(ILogger _logger) + { + logger = _logger; + } + + /// + /// Please only use this to get table that have a respective file (i.e. CharacterExcelTable have characterexceltable.bytes) + /// + /// + /// + /// + public T GetTable() where T : IFlatbufferObject + { + var type = typeof(T); + + if (caches.TryGetValue(type, out var cache)) + return (T)cache; + + var bytesFilePath = Path.Join(Path.GetDirectoryName(AppContext.BaseDirectory), "Resources/excel/", $"{type.Name.ToLower()}.bytes"); + if (!File.Exists(bytesFilePath)) + { + throw new FileNotFoundException($"bytes files for {type.Name} not found"); + } + + var bytes = File.ReadAllBytes(bytesFilePath); + TableEncryptionService.XOR(type.Name, bytes); + var inst = type.GetMethod($"GetRootAs{type.Name}", BindingFlags.Static | BindingFlags.Public, [typeof(ByteBuffer)])!.Invoke(null, [new ByteBuffer(bytes)]); + + caches.Add(type, inst!); + logger.LogDebug("{Excel} loaded and cached", type.Name); + + return (T)inst!; + } + } + + internal static class ExcelTableServiceExtensions + { + public static void AddExcelTableService(this IServiceCollection services) + { + services.AddSingleton(); + } + } +} diff --git a/SCHALE.GameServer/Services/SessionKeyService.cs b/SCHALE.GameServer/Services/SessionKeyService.cs index f17b468..e74271b 100644 --- a/SCHALE.GameServer/Services/SessionKeyService.cs +++ b/SCHALE.GameServer/Services/SessionKeyService.cs @@ -17,8 +17,11 @@ namespace SCHALE.GameServer.Services context = _context; } - public AccountDB GetAccount(SessionKey sessionKey) + public AccountDB GetAccount(SessionKey? sessionKey) { + if (sessionKey is null) + throw new WebAPIException(WebAPIErrorCode.InvalidSession, "SessionKey not received"); + if (sessions.TryGetValue(sessionKey.AccountServerId, out Guid token) && token.ToString() == sessionKey.MxToken) { var account = context.Accounts.SingleOrDefault(x => x.ServerId == sessionKey.AccountServerId); @@ -53,7 +56,7 @@ namespace SCHALE.GameServer.Services } } - internal static class ServiceExtensions + internal static class SessionKeyServiceExtensions { public static void AddMemorySessionKeyService(this IServiceCollection services) { @@ -64,6 +67,6 @@ namespace SCHALE.GameServer.Services public interface ISessionKeyService { public SessionKey? Create(long publisherAccountId); - public AccountDB GetAccount(SessionKey sessionKey); + public AccountDB GetAccount(SessionKey? sessionKey); } } diff --git a/SCHALE.GameServer/appsettings.json b/SCHALE.GameServer/appsettings.json index d889eb5..b25dd22 100644 --- a/SCHALE.GameServer/appsettings.json +++ b/SCHALE.GameServer/appsettings.json @@ -1,4 +1,14 @@ { + "Kestrel": { + "EndPoints": { + "Http": { + "Url": "http://0.0.0.0:80" + }, + "Https": { + "Url": "https://0.0.0.0:443" + } + } + }, "Serilog": { "MinimumLevel": { "Default": "Information", @@ -9,7 +19,7 @@ } }, "ConnectionStrings": { - "MongoDB": "mongodb://localhost:27017/SCHALE" + "SQLServer": "data source=localhost\\SQLEXPRESS;initial catalog=schale;trusted_connection=true;TrustServerCertificate=True" }, "AllowedHosts": "*" } diff --git a/Scripts/migrate.ps1 b/Scripts/migrate.ps1 new file mode 100644 index 0000000..0c571be --- /dev/null +++ b/Scripts/migrate.ps1 @@ -0,0 +1,40 @@ +[CmdletBinding()] +param( + [Parameter(ValueFromRemainingArguments)] + [string[]]$Arguments +) + +$ScriptDir = ([IO.Path]::GetDirectoryName($MyInvocation.MyCommand.Source)) +$CommonProjectPath = ([IO.Path]::Join($ScriptDir, "..\SCHALE.Common\SCHALE.Common.csproj")) +$GameServerProjectPath = ([IO.Path]::Join($ScriptDir, "..\SCHALE.GameServer\SCHALE.GameServer.csproj")) + +if ($Arguments.Length -lt 1 -Or $Arguments[0].Equals("-h") -Or $Arguments[0].Equals("--help")) +{ + Write-Output @" +Commands + -h|--help shows this help output + undo expands to dotnet ef migrations remove, undo latest migration + create expands to dotnet ef migrations add, second positional argument will be the migration name + +Examples + migrate.ps1 create Test + migrate.ps1 undo +"@ +exit +} + +Switch ($Arguments[0]) +{ + "undo" + { + dotnet ef migrations remove --project $CommonProjectPath --startup-project $GameServerProjectPath --context SCHALEContext + } + "create" + { + dotnet ef migrations add $Arguments[1] --project $CommonProjectPath --startup-project $GameServerProjectPath --context SCHALEContext + } + default + { + Write-Host "Invalid operation" $Arguments[0] + } +} \ No newline at end of file