diff --git a/README.md b/README.md index 9f2baf7..3208808 100644 --- a/README.md +++ b/README.md @@ -1 +1,4 @@ -# SCHALE.GameServer \ No newline at end of file +# SCHALE.GameServer + +## Connecting +- Run the game with this [frida script](https://gist.githubusercontent.com/raphaeIl/c4ca030411186c9417da22d8d7864c4d/raw/00b69c5bacdf79c24972411bd80d785eed3841ce/ba.js) \ No newline at end of file diff --git a/SCHALE.Common/Database/SCHALEContext.cs b/SCHALE.Common/Database/SCHALEContext.cs index 5106e21..5983715 100644 --- a/SCHALE.Common/Database/SCHALEContext.cs +++ b/SCHALE.Common/Database/SCHALEContext.cs @@ -68,7 +68,8 @@ namespace SCHALE.Common.Database .WithOne(x => x.Account) .HasForeignKey(x => x.AccountServerId) .IsRequired(); - + + modelBuilder.Entity(x => x.Property(b => b.RaidInfo).HasJsonConversion()); modelBuilder.Entity().Property(x => x.ServerId).ValueGeneratedOnAdd(); modelBuilder.Entity().Property(x => x.ServerId).ValueGeneratedOnAdd(); modelBuilder.Entity().Property(x => x.ServerId).ValueGeneratedOnAdd(); diff --git a/SCHALE.Common/Database/dbs.cs b/SCHALE.Common/Database/dbs.cs index 5b1c9fb..e85b167 100644 --- a/SCHALE.Common/Database/dbs.cs +++ b/SCHALE.Common/Database/dbs.cs @@ -13,13 +13,130 @@ namespace SCHALE.Common.Database } - // Battle? probably need to implement these our selves - public class BattleSummary + public struct RaidBossResult : IEquatable { + [JsonIgnore] + public int Index { get; set; } + [JsonIgnore] + public long GivenDamage { get; set; } + + [JsonIgnore] + public long GivenGroggyPoint { get; set; } + + //public RaidDamage RaidDamage { get; set; } + + public long EndHpRateRawValue { readonly get; set; } + + public long GroggyRateRawValue { readonly get; set; } + + public int GroggyCount { readonly get; set; } + + public List SubPartsHPs { readonly get; set; } + + public long AIPhase { readonly get; set; } + + public bool Equals(RaidBossResult other) + { + return this.Index == other.Index; + } + } + + public class RaidBossResultCollection : KeyedCollection + { + [JsonIgnore] + public int LastIndex { get; set; } + + [JsonIgnore] + public long TotalDamage { get; set; } + + [JsonIgnore] + public long CurrentDamage { get; set; } + + [JsonIgnore] + public long TotalGroggyPoint { get; set; } + + [JsonIgnore] + public long CurrentGroggyPoint { get; set; } + + [JsonIgnore] + public int TotalGroggyCount { get; set; } + + protected override int GetKeyForItem(RaidBossResult item) + { + return item.Index; + } + } + + public class RaidSummary + { + public long RaidSeasonId { get; set; } + + public long GivenDamage { get; set; } + + public int TotalGroggyCount { get; set; } + + public int RaidBossIndex { get; set; } + + public RaidBossResultCollection RaidBossResults { get; set; } + } + + // Battle? probably need to implement these our selves + public class BattleSummary : IEquatable + { + public long HashKey { get; set; } + + public bool IsBossBattle { get; set; } + + //public BattleTypes BattleType { get; set; } + + public long StageId { get; set; } + + public long GroundId { get; set; } + + //public GroupTag Winner { get; set; } + + [JsonIgnore] + public bool IsPlayerWin { get; set; } + + //public BattleEndType EndType { get; set; } + + public int EndFrame { get; set; } + + //public GroupSummary Group01Summary { get; set; } + + //public GroupSummary Group02Summary { get; set; } + + //public WeekDungeonSummary WeekDungeonSummary { get; set; } + + public RaidSummary RaidSummary { get; set; } + + //public ArenaSummary ArenaSummary { get; set; } + + [JsonIgnore] + public TimeSpan EndTime { get; set; } + + public int ContinueCount { get; set; } + + public float ElapsedRealtime { get; set; } + + [JsonIgnore] + public string FindGiftClearText { get; set; } + + [JsonIgnore] + public long EventContentId { get; set; } + + [JsonIgnore] + public long FixedEchelonId { get; set; } + + public bool IsAbort { get; set; } + + public bool Equals(BattleSummary? other) + { + return this.HashKey == other.HashKey; + } } - // probably just a simple json wrapper public class TypedJsonWrapper { @@ -189,6 +306,19 @@ namespace SCHALE.Common.Database public Dictionary UpdateTimeDict { get; set; } } + public class RaidInfo // custom class for all raid stuff needed + { + public long SeasonId { get; set; } + + public long CurrentRaidUniqueId { get; set; } + + public Difficulty CurrentDifficulty { get; set; } + + public long BestRankingPoint { get; set; } + + public long TotalRankingPoint { get; set; } + } + public class AccountDB { [JsonIgnore] @@ -212,9 +342,8 @@ namespace SCHALE.Common.Database [JsonIgnore] public virtual ICollection Gears { get; } - [JsonIgnore] - public long RaidSeasonId { get; set; } // idk where to store this + public virtual RaidInfo RaidInfo { get; set; } public AccountDB() { } @@ -225,6 +354,12 @@ namespace SCHALE.Common.Database Level = 1; LastConnectTime = DateTime.Now; CreateDate = DateTime.Now; + RaidInfo = new() + { + SeasonId = 1, // default + BestRankingPoint = 0, + TotalRankingPoint = 0, + }; } [Key] diff --git a/SCHALE.Common/Migrations/20240519215605_AccountDB_RaidInfo.Designer.cs b/SCHALE.Common/Migrations/20240519215605_AccountDB_RaidInfo.Designer.cs new file mode 100644 index 0000000..07a03e1 --- /dev/null +++ b/SCHALE.Common/Migrations/20240519215605_AccountDB_RaidInfo.Designer.cs @@ -0,0 +1,522 @@ +// +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("20240519215605_AccountDB_RaidInfo")] + partial class AccountDB_RaidInfo + { + /// + 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("RaidInfo") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + 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.EquipmentDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("BoundCharacterServerId") + .HasColumnType("bigint"); + + b.Property("Exp") + .HasColumnType("bigint"); + + b.Property("IsLocked") + .HasColumnType("bit"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("StackCount") + .HasColumnType("bigint"); + + b.Property("Tier") + .HasColumnType("int"); + + b.Property("UniqueId") + .HasColumnType("bigint"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("Equipment"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.GearDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("BoundCharacterServerId") + .HasColumnType("bigint"); + + b.Property("Exp") + .HasColumnType("bigint"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("SlotIndex") + .HasColumnType("bigint"); + + b.Property("Tier") + .HasColumnType("int"); + + b.Property("UniqueId") + .HasColumnType("bigint"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("Gears"); + }); + + 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.WeaponDB", b => + { + b.Property("ServerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("ServerId")); + + b.Property("AccountServerId") + .HasColumnType("bigint"); + + b.Property("BoundCharacterServerId") + .HasColumnType("bigint"); + + b.Property("Exp") + .HasColumnType("bigint"); + + b.Property("IsLocked") + .HasColumnType("bit"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("StarGrade") + .HasColumnType("int"); + + b.Property("UniqueId") + .HasColumnType("bigint"); + + b.HasKey("ServerId"); + + b.HasIndex("AccountServerId"); + + b.ToTable("Weapons"); + }); + + 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.EquipmentDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("Equipment") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.GearDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("Gears") + .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.WeaponDB", b => + { + b.HasOne("SCHALE.Common.Database.AccountDB", "Account") + .WithMany("Weapons") + .HasForeignKey("AccountServerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("SCHALE.Common.Database.AccountDB", b => + { + b.Navigation("Characters"); + + b.Navigation("Echelons"); + + b.Navigation("Equipment"); + + b.Navigation("Gears"); + + b.Navigation("Items"); + + b.Navigation("MissionProgresses"); + + b.Navigation("Weapons"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SCHALE.Common/Migrations/20240519215605_AccountDB_RaidInfo.cs b/SCHALE.Common/Migrations/20240519215605_AccountDB_RaidInfo.cs new file mode 100644 index 0000000..7bb4ea0 --- /dev/null +++ b/SCHALE.Common/Migrations/20240519215605_AccountDB_RaidInfo.cs @@ -0,0 +1,40 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace SCHALE.Common.Migrations +{ + /// + public partial class AccountDB_RaidInfo : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "RaidSeasonId", + table: "Accounts"); + + migrationBuilder.AddColumn( + name: "RaidInfo", + table: "Accounts", + type: "nvarchar(max)", + nullable: false, + defaultValue: ""); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "RaidInfo", + table: "Accounts"); + + migrationBuilder.AddColumn( + name: "RaidSeasonId", + table: "Accounts", + type: "bigint", + nullable: false, + defaultValue: 0L); + } + } +} diff --git a/SCHALE.Common/Migrations/SCHALEContextModelSnapshot.cs b/SCHALE.Common/Migrations/SCHALEContextModelSnapshot.cs index cf8f6d7..1882211 100644 --- a/SCHALE.Common/Migrations/SCHALEContextModelSnapshot.cs +++ b/SCHALE.Common/Migrations/SCHALEContextModelSnapshot.cs @@ -75,8 +75,9 @@ namespace SCHALE.Common.Migrations b.Property("PublisherAccountId") .HasColumnType("bigint"); - b.Property("RaidSeasonId") - .HasColumnType("bigint"); + b.Property("RaidInfo") + .IsRequired() + .HasColumnType("nvarchar(max)"); b.Property("RepresentCharacterServerId") .HasColumnType("int"); diff --git a/SCHALE.GameServer/Commands/SetAccountCommand.cs b/SCHALE.GameServer/Commands/SetAccountCommand.cs index 86c5a65..105d257 100644 --- a/SCHALE.GameServer/Commands/SetAccountCommand.cs +++ b/SCHALE.GameServer/Commands/SetAccountCommand.cs @@ -20,7 +20,7 @@ namespace SCHALE.GameServer.Commands public override void Execute() { PropertyInfo? targetProperty = typeof(AccountDB).GetProperty(Property) ?? typeof(AccountDB).GetProperty(Property.Capitalize()); - + if (targetProperty != null) { TypeConverter converter = TypeDescriptor.GetConverter(targetProperty.PropertyType); @@ -39,9 +39,30 @@ namespace SCHALE.GameServer.Commands { throw new ArgumentException("Invalid Value"); } - } + } } + else if (Property.Equals("raidseasonid", StringComparison.CurrentCultureIgnoreCase)) // temp raid stuff + { + if (long.TryParse(Value, out long seasonId)) + { + connection.Account.RaidInfo = new RaidInfo() + { + SeasonId = seasonId, + BestRankingPoint = 0, + TotalRankingPoint = 0, + }; + + connection.SendChatMessage($"Set Raid SeasonId to: {seasonId}"); + connection.Context.SaveChanges(); + } + + else + { + throw new ArgumentException("Invalid Value"); + } + } + else { throw new ArgumentException("Invalid Player Property!"); diff --git a/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Raid.cs b/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Raid.cs index a788f03..6726269 100644 --- a/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Raid.cs +++ b/SCHALE.GameServer/Controllers/Api/ProtocolHandlers/Raid.cs @@ -1,6 +1,7 @@ using SCHALE.Common.Database; using SCHALE.Common.FlatData; using SCHALE.Common.NetworkProtocol; +using SCHALE.GameServer.Managers; using SCHALE.GameServer.Services; namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers @@ -23,24 +24,87 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers { var account = sessionKeyService.GetAccount(req.SessionKey); - var raidSeasonInfo = excelTableService.GetTable().UnPack().DataList; - var targetSeason = raidSeasonInfo.FirstOrDefault(x => x.SeasonId == account.RaidSeasonId); + var raidSeasonExcel = excelTableService.GetTable().UnPack().DataList; + var targetSeason = raidSeasonExcel.FirstOrDefault(x => x.SeasonId == account.RaidInfo.SeasonId); return new RaidLobbyResponse() { SeasonType = RaidSeasonType.Open, - RaidLobbyInfoDB = new() - { - SeasonId = account.RaidSeasonId, - Tier = 2, - Ranking = 1, - BestRankingPoint = 1_000_000, - TotalRankingPoint = 10_000_000, - ReceiveRewardIds = targetSeason.SeasonRewardId, - PlayableHighestDifficulty = new() { - { targetSeason.OpenRaidBossGroup.FirstOrDefault(), Difficulty.Torment } - } - } + RaidLobbyInfoDB = RaidManager.Instance.GetLobby(account.RaidInfo, targetSeason), + }; + } + + [ProtocolHandler(Protocol.Raid_CreateBattle)] + public ResponsePacket CreateBattleHandler(RaidCreateBattleRequest req) + { + var account = sessionKeyService.GetAccount(req.SessionKey); + + account.RaidInfo.CurrentRaidUniqueId = req.RaidUniqueId; + account.RaidInfo.CurrentDifficulty = req.Difficulty; + + context.Entry(account).Property(x => x.RaidInfo).IsModified = true; // force update + context.SaveChanges(); + + var raid = RaidManager.Instance.CreateRaid(account.RaidInfo, account.ServerId, account.Nickname, req.IsPractice, req.RaidUniqueId); + var battle = RaidManager.Instance.CreateBattle(account.ServerId, account.Nickname, req.RaidUniqueId); + + return new RaidCreateBattleResponse() + { + RaidDB = raid, + RaidBattleDB = battle, + AssistCharacterDB = new () { } + }; + } + + [ProtocolHandler(Protocol.Raid_EnterBattle)] // clicked restart + public ResponsePacket EnterBattleHandler(RaidEnterBattleRequest req) + { + var raid = RaidManager.Instance.RaidDB; + var battle = RaidManager.Instance.RaidBattleDB; + + return new RaidEnterBattleResponse() + { + RaidDB = raid, + RaidBattleDB = battle, + AssistCharacterDB = new() { } + }; + } + + [ProtocolHandler(Protocol.Raid_EndBattle)] + public ResponsePacket EndBattleHandler(RaidEndBattleRequest req) + { + var account = sessionKeyService.GetAccount(req.SessionKey); + + var raidStageTable = excelTableService.GetTable().UnPack().DataList; + var currentRaidData = raidStageTable.FirstOrDefault(x => x.Id == account.RaidInfo.CurrentRaidUniqueId); + + var timeScore = RaidManager.CalculateTimeScore(req.Summary.ElapsedRealtime, account.RaidInfo.CurrentDifficulty); + var hpPercentScorePoint = currentRaidData.HPPercentScore; + var defaultClearPoint = currentRaidData.DefaultClearScore; + + var rankingPoint = timeScore + hpPercentScorePoint + defaultClearPoint; + + account.RaidInfo.BestRankingPoint = rankingPoint > account.RaidInfo.BestRankingPoint ? rankingPoint : account.RaidInfo.BestRankingPoint; + account.RaidInfo.TotalRankingPoint += rankingPoint; + context.Entry(account).Property(x => x.RaidInfo).IsModified = true; // force update + context.SaveChanges(); + + // saving battle result to continue on next attempt doesn't work + var battle = RaidManager.Instance.RaidBattleDB; + var bossResult = req.Summary.RaidSummary.RaidBossResults.FirstOrDefault(); + + battle.CurrentBossHP = bossResult.EndHpRateRawValue; + battle.CurrentBossGroggy = bossResult.GroggyRateRawValue; + battle.CurrentBossAIPhase = bossResult.AIPhase; + battle.SubPartsHPs = bossResult.SubPartsHPs; + + return new RaidEndBattleResponse() + { + RankingPoint = rankingPoint, + BestRankingPoint = account.RaidInfo.BestRankingPoint, + ClearTimePoint = timeScore, + HPPercentScorePoint = hpPercentScorePoint, + DefaultClearPoint = defaultClearPoint }; } @@ -52,71 +116,5 @@ namespace SCHALE.GameServer.Controllers.Api.ProtocolHandlers OpponentUserDBs = [] }; } - - [ProtocolHandler(Protocol.Raid_CreateBattle)] - public ResponsePacket CreateBattleHandller(RaidCreateBattleRequest req) - { - var account = sessionKeyService.GetAccount(req.SessionKey); - - var raidStageTable = excelTableService.GetTable().UnPack().DataList; - var currentRaid = raidStageTable.FirstOrDefault(x => x.Id == req.RaidUniqueId); - - return new RaidCreateBattleResponse() - { - RaidDB = new() - { - Owner = new() - { - AccountId = account.ServerId, - AccountName = account.Nickname, - }, - ContentType = ContentType.Raid, - UniqueId = req.RaidUniqueId, - SeasonId = account.RaidSeasonId, - PlayerCount = 1, - RaidState = RaidStatus.Playing, - IsPractice = req.IsPractice, - RaidBossDBs = [ - new() { - ContentType = ContentType.Raid, - BossCurrentHP = long.MaxValue - } - ], - AccountLevelWhenCreateDB = account.Level, - }, - - RaidBattleDB = new() - { - ContentType = ContentType.Raid, - RaidUniqueId = req.RaidUniqueId, - CurrentBossHP = long.MaxValue, - RaidMembers = [ - new() { - AccountId = account.ServerId, - AccountName = account.Nickname, - } - ] - }, - - AssistCharacterDB = new () { } - }; - } - - [ProtocolHandler(Protocol.Raid_EnterBattle)] // clicked restart - public ResponsePacket EnterBattleHandler(RaidEnterBattleRequest req) - { - return new RaidEnterBattleResponse() - { - - }; - } - - [ProtocolHandler(Protocol.Raid_EndBattle)] - public ResponsePacket EndBattleHandler(RaidEndBattleRequest req) - { - return new RaidEndBattleResponse() - { - }; - } } } diff --git a/SCHALE.GameServer/Managers/RaidManager.cs b/SCHALE.GameServer/Managers/RaidManager.cs new file mode 100644 index 0000000..c3acc69 --- /dev/null +++ b/SCHALE.GameServer/Managers/RaidManager.cs @@ -0,0 +1,115 @@ +using SCHALE.Common.Database; +using SCHALE.Common.FlatData; +using SCHALE.Common.NetworkProtocol; +using SCHALE.GameServer.Controllers.Api.ProtocolHandlers; +using SCHALE.GameServer.Utils; + +namespace SCHALE.GameServer.Managers +{ + public class RaidManager : Singleton + { + public SingleRaidLobbyInfoDB RaidLobbyInfoDB { get; private set; } + + public RaidDB RaidDB { get; private set; } + + public RaidBattleDB RaidBattleDB { get; private set; } + + public SingleRaidLobbyInfoDB GetLobby(RaidInfo raidInfo, RaidSeasonManageExcelT targetSeasonData) + { + if (RaidLobbyInfoDB == null || RaidLobbyInfoDB.SeasonId != raidInfo.SeasonId) + { + RaidLobbyInfoDB = new SingleRaidLobbyInfoDB() + { + Tier = 0, + Ranking = 1, + SeasonId = raidInfo.SeasonId, + BestRankingPoint = 0, + TotalRankingPoint = 0, + ReceiveRewardIds = targetSeasonData.SeasonRewardId, + PlayableHighestDifficulty = new() + { + { targetSeasonData.OpenRaidBossGroup.FirstOrDefault(), Difficulty.Torment } + } + }; + } + + else + { + RaidLobbyInfoDB.BestRankingPoint = raidInfo.BestRankingPoint; + RaidLobbyInfoDB.TotalRankingPoint = raidInfo.TotalRankingPoint; + } + + return RaidLobbyInfoDB; + } + + public RaidDB CreateRaid(RaidInfo raidInfo, long ownerId, string ownerNickname, bool isPractice, long raidId) + { + if (RaidDB == null) + { + RaidDB = new() + { + Owner = new() + { + AccountId = ownerId, + AccountName = ownerNickname, + }, + + ContentType = ContentType.Raid, + UniqueId = raidId, + SeasonId = raidInfo.SeasonId, + RaidState = RaidStatus.Playing, + IsPractice = isPractice, + BossDifficulty = raidInfo.CurrentDifficulty, + RaidBossDBs = [ + new() { + ContentType = ContentType.Raid, + BossCurrentHP = long.MaxValue + } + ], + }; + } + + else + { + RaidDB.BossDifficulty = raidInfo.CurrentDifficulty; + RaidDB.UniqueId = raidId; + RaidDB.IsPractice = isPractice; + } + + return RaidDB; + } + + public RaidBattleDB CreateBattle(long ownerId, string ownerNickname, long raidId) + { + if (RaidBattleDB == null) + { + RaidBattleDB = new() + { + ContentType = ContentType.Raid, + RaidUniqueId = raidId, + CurrentBossHP = long.MaxValue, + RaidMembers = [ + new() { + AccountId = ownerId, + AccountName = ownerNickname, + } + ] + }; + } + + else + { + RaidBattleDB.RaidUniqueId = raidId; + } + + return RaidBattleDB; + } + + public static long CalculateTimeScore(float duration, Difficulty difficulty) + { + int[] multipliers = [120, 240, 480, 960, 1440, 1920, 2400]; // from wiki + + return (long)((3600f - duration) * multipliers[(int)difficulty]); + } + } +}