diff --git a/AscNet.Common/Database/Character.cs b/AscNet.Common/Database/Character.cs index d8cbd8c..35e00c9 100644 --- a/AscNet.Common/Database/Character.cs +++ b/AscNet.Common/Database/Character.cs @@ -4,6 +4,7 @@ using MongoDB.Driver; using AscNet.Table.share.character; using AscNet.Table.share.character.skill; using AscNet.Common.MsgPack; +using AscNet.Common.Util; namespace AscNet.Common.Database { @@ -83,6 +84,41 @@ namespace AscNet.Common.Database Characters.Add(characterData); } + public UpgradeCharacterResult UpgradeCharacterSkillGroup(uint skillGroupId, int count) + { + List affectedCharacters = new(); + int totalCoinCost = 0; + int totalSkillPointCost = 0; + IEnumerable affectedSkills = CharacterSkillGroupTableReader.Instance.All.Where(x => x.Id == skillGroupId).SelectMany(x => x.SkillId); + + foreach (var skillId in affectedSkills) + { + foreach (var character in Characters.Where(x => x.SkillList.Any(x => x.Id == skillId))) + { + var characterSkill = character.SkillList.First(x => x.Id == skillId); + int targetLevel = characterSkill.Level + count; + + while (characterSkill.Level < targetLevel) + { + var skillUpgrade = CharacterSkillUpgradeTableReader.Instance.All.FirstOrDefault(x => x.SkillId == skillId && Miscs.ParseIntOr(x.Level) == characterSkill.Level); + + totalCoinCost += Miscs.ParseIntOr(skillUpgrade?.UseCoin); + totalSkillPointCost += Miscs.ParseIntOr(skillUpgrade?.UseSkillPoint); + + characterSkill.Level++; + } + affectedCharacters.Add(character.Id); + } + } + + return new UpgradeCharacterResult() + { + AffectedCharacters = affectedCharacters, + CoinCost = totalCoinCost, + SkillPointCost = totalSkillPointCost + }; + } + public void AddEquip(uint equipId, int characterId = 0) { NotifyEquipDataList.NotifyEquipDataListEquipData equipData = new() @@ -128,4 +164,11 @@ namespace AscNet.Common.Database [BsonRequired] public List Fashions { get; set; } } + + public struct UpgradeCharacterResult + { + public int CoinCost { get; init; } + public int SkillPointCost { get; init; } + public List AffectedCharacters { get; init; } + } } diff --git a/AscNet.Common/Database/Inventory.cs b/AscNet.Common/Database/Inventory.cs index c2ff2c5..2bed8e1 100644 --- a/AscNet.Common/Database/Inventory.cs +++ b/AscNet.Common/Database/Inventory.cs @@ -9,6 +9,34 @@ namespace AscNet.Common.Database #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. public class Inventory { + #region CommonItems + public const int Coin = 1; + public const int PaidGem = 2; + public const int FreeGem = 3; + public const int ActionPoint = 4; + public const int HongKa = 5; + public const int TeamExp = 7; + public const int AndroidHongKa = 8; + public const int IosHongKa = 10; + public const int SkillPoint = 12; + public const int DailyActiveness = 13; + public const int WeeklyActiveness = 14; + public const int HostelElectric = 15; + public const int HostelMat = 16; + public const int OnlineBossTicket = 17; + public const int BountyTaskExp = 18; + public const int DormCoin = 30; + public const int FurnitureCoin = 31; + public const int DormEnterIcon = 36; + public const int BaseEquipCoin = 300; + public const int InfestorActionPoint = 50; + public const int InfestorMoney = 51; + public const int PokemonLevelUpItem = 56; + public const int PokemonStarUpItem = 57; + public const int PokemonLowStarUpItem = 58; + public const int PassportExp = 60; + #endregion + public static readonly IMongoCollection collection = Common.db.GetCollection("inventory"); public static Inventory FromUid(long uid) @@ -41,6 +69,26 @@ namespace AscNet.Common.Database return inventory; } + public void Do(int itemId, int amount) + { + Item? item = Items.FirstOrDefault(x => x.Id == itemId); + if (item is not null) + { + item.Count += amount; + item.RefreshTime = DateTimeOffset.Now.ToUnixTimeSeconds(); + } + else + { + Items.Add(new Item() + { + Id = itemId, + Count = amount, + RefreshTime = DateTimeOffset.Now.ToUnixTimeSeconds(), + CreateTime = DateTimeOffset.Now.ToUnixTimeSeconds() + }); + } + } + public void Save() { collection.ReplaceOne(Builders.Filter.Eq(x => x.Id, Id), this); diff --git a/AscNet.Common/MsgPack/Types.cs b/AscNet.Common/MsgPack/Types.cs index dc5d7c1..5f86323 100644 --- a/AscNet.Common/MsgPack/Types.cs +++ b/AscNet.Common/MsgPack/Types.cs @@ -2002,19 +2002,7 @@ namespace AscNet.Common.MsgPack [global::MessagePack.MessagePackObject(true)] public class NotifyItemDataList { - [global::MessagePack.MessagePackObject(true)] - public class NotifyItemDataListItemData - { - public Int32 Id { get; set; } - public UInt32 Count { get; set; } - public Int32 BuyTimes { get; set; } - public Int32 TotalBuyTimes { get; set; } - public Int32 LastBuyTime { get; set; } - public UInt32 RefreshTime { get; set; } - public UInt32 CreateTime { get; set; } - } - - public List ItemDataList { get; set; } = new(); + public List ItemDataList { get; set; } = new(); public dynamic? ItemRecycleDict { get; set; } } diff --git a/AscNet.GameServer/Handlers/AccountModule.cs b/AscNet.GameServer/Handlers/AccountModule.cs index 26da99f..b595e82 100644 --- a/AscNet.GameServer/Handlers/AccountModule.cs +++ b/AscNet.GameServer/Handlers/AccountModule.cs @@ -182,7 +182,7 @@ namespace AscNet.GameServer.Handlers Id = "0", Status = 0, // MAIL_STATUS_UNREAD SendName = "AscNet Developers", - Title = "[IMPORTANT] Important Info Regarding This Server Software", + Title = "[IMPORTANT] Information Regarding This Server Software [有关本服务器软件的信息]", Content = @"Hello Commandant! Welcome to AscNet, we are happy that you are using this Server Software. This Server Software is always free and if you are paying to gain access to this you are being SCAMMED, we encourage you to help prevent another buyer like you by making a PSA or telling others whom you may see as potential users. @@ -190,7 +190,8 @@ Sorry for the inconvinience. 欢迎来到 AscNet,我们很高兴您使用本服务器软件。 本服务器软件始终是免费的,如果您是通过付费来使用本软件,那您就被骗了,我们鼓励您告诉其他潜在用户,以防止再有像您这样的买家。 -不便之处,敬请原谅。", +不便之处,敬请原谅。 +[中文版为机器翻译,准确内容请参考英文信息]", CreateTime = ((DateTimeOffset)Process.GetCurrentProcess().StartTime).ToUnixTimeSeconds(), SendTime = ((DateTimeOffset)Process.GetCurrentProcess().StartTime).ToUnixTimeSeconds(), ExpireTime = DateTimeOffset.Now.ToUnixTimeSeconds() * 2, diff --git a/AscNet.GameServer/Handlers/CharacterModule.cs b/AscNet.GameServer/Handlers/CharacterModule.cs new file mode 100644 index 0000000..95083ca --- /dev/null +++ b/AscNet.GameServer/Handlers/CharacterModule.cs @@ -0,0 +1,29 @@ +using AscNet.Common.Database; +using AscNet.Common.MsgPack; + +namespace AscNet.GameServer.Handlers +{ + internal class CharacterModule + { + [RequestPacketHandler("CharacterUpgradeSkillGroupRequest")] + public static void CharacterUpgradeSkillGroupRequestHandler(Session session, Packet.Request packet) + { + CharacterUpgradeSkillGroupRequest request = packet.Deserialize(); + + var upgradeResult = session.character.UpgradeCharacterSkillGroup(request.SkillGroupId, request.Count); + session.inventory.Do(Inventory.Coin, upgradeResult.CoinCost * -1); + session.inventory.Do(Inventory.SkillPoint, upgradeResult.SkillPointCost * -1); + + NotifyCharacterDataList notifyCharacterData = new(); + notifyCharacterData.CharacterDataList.AddRange(session.character.Characters.Where(x => upgradeResult.AffectedCharacters.Contains(x.Id))); + + NotifyItemDataList notifyItemData = new(); + notifyItemData.ItemDataList.AddRange(session.inventory.Items.Where(x => x.Id == Inventory.Coin || x.Id == Inventory.SkillPoint)); + + session.SendPush(notifyCharacterData); + session.SendPush(notifyItemData); + + session.SendResponse(new CharacterUpgradeSkillGroupResponse(), packet.Id); + } + } +} diff --git a/AscNet.GameServer/Handlers/MailModule.cs b/AscNet.GameServer/Handlers/MailModule.cs index 59bedf0..7e140fc 100644 --- a/AscNet.GameServer/Handlers/MailModule.cs +++ b/AscNet.GameServer/Handlers/MailModule.cs @@ -21,7 +21,6 @@ namespace AscNet.GameServer.Handlers internal class MailModule { - [RequestPacketHandler("MailReadRequest")] public static void MailReadRequestHandler(Session session, Packet.Request packet) { diff --git a/AscNet.GameServer/Packet.cs b/AscNet.GameServer/Packet.cs index 2716efc..1a0a392 100644 --- a/AscNet.GameServer/Packet.cs +++ b/AscNet.GameServer/Packet.cs @@ -1,4 +1,6 @@ -using System.Reflection; +using System.Net.Sockets; +using System.Reflection; +using AscNet.Common.MsgPack; using AscNet.Logging; using MessagePack; @@ -36,6 +38,11 @@ namespace AscNet.GameServer [Key(2)] public byte[] Content; + + public T Deserialize() + { + return MessagePackSerializer.Deserialize(Content); + } } [MessagePackObject(false)]