From e69b8541af8b286775e15b737229255ad41bd344 Mon Sep 17 00:00:00 2001 From: rfi Date: Sat, 2 Dec 2023 14:28:19 +0700 Subject: [PATCH] sussy 2.9 changes, and finally shard unlock implementation --- AscNet.Common/Common.cs | 10 +++ AscNet.Common/Database/Character.cs | 46 +++++++++--- AscNet.Common/MsgPack/Types.cs | 9 ++- AscNet.GameServer/Handlers/CharacterModule.cs | 74 +++++++++++++++++++ AscNet.GameServer/Handlers/FightModule.cs | 6 ++ AscNet.GameServer/Handlers/ItemModule.cs | 35 +++++++++ AscNet.GameServer/Handlers/PlayerModule.cs | 19 +++++ .../Controllers/AccountController.cs | 2 +- .../Controllers/ConfigController.cs | 32 +++++--- AscNet.SDKServer/SDKServer.cs | 4 + Resources/Configs/version_config.json | 7 ++ 11 files changed, 223 insertions(+), 21 deletions(-) create mode 100644 AscNet.GameServer/Handlers/ItemModule.cs diff --git a/AscNet.Common/Common.cs b/AscNet.Common/Common.cs index 7c5c8a1..0d389e9 100644 --- a/AscNet.Common/Common.cs +++ b/AscNet.Common/Common.cs @@ -58,4 +58,14 @@ namespace AscNet.Common } } } + public class ServerCodeException : Exception + { + public int Code { get; set; } + + public ServerCodeException(string message, int code) + : base(message) + { + Code = code; + } + } } diff --git a/AscNet.Common/Database/Character.cs b/AscNet.Common/Database/Character.cs index 38286f4..09165dc 100644 --- a/AscNet.Common/Database/Character.cs +++ b/AscNet.Common/Database/Character.cs @@ -7,6 +7,7 @@ using AscNet.Common.MsgPack; using AscNet.Common.Util; using Newtonsoft.Json; using AscNet.Table.V2.share.equip; +using AscNet.Table.V2.share.character.quality; namespace AscNet.Common.Database { @@ -53,23 +54,36 @@ namespace AscNet.Common.Database return character; } - public void AddCharacter(uint id) + /// + /// Don't forget to send Equip, Fashion, and the Character notify after using this! + /// + /// + /// + public AddCharacterRet AddCharacter(uint id) { + AddCharacterRet ret = new(); CharacterTable? character = CharacterTableReader.Instance.FromId((int)id); CharacterSkillTable? characterSkill = CharacterSkillTableReader.Instance.FromCharacterId((int)id); + CharacterQualityTable? characterQuality = TableReaderV2.Parse().OrderBy(x => x.Quality).FirstOrDefault(x => x.CharacterId == id); - if (character is null || characterSkill is null) - throw new ArgumentException("Invalid character id!", nameof(id)); + if (character is null || characterSkill is null || characterQuality is null) + { + // CharacterManagerGetCharacterDataNotFound + throw new ServerCodeException("Invalid character id!", 20009021); + } if (Characters.FirstOrDefault(x => x.Id == character.Id) is not null) - throw new ArgumentException("Character already obtained!", nameof(id)); + { + // CharacterManagerCreateCharacterAlreadyExist + throw new ServerCodeException("Character already obtained!", 20009022); + } NotifyCharacterDataList.NotifyCharacterDataListCharacterData characterData = new() { Id = (uint)character.Id, Level = 1, Exp = 0, - Quality = 1, - InitQuality = 1, + Quality = characterQuality.Quality, + InitQuality = characterQuality.Quality, Star = 0, Grade = 1, FashionId = (uint)character.DefaultNpcFashtionId, @@ -89,15 +103,19 @@ namespace AscNet.Common.Database Id = uint.Parse(x.ToString().Take(6).ToArray()), Level = 1 })); - Fashions.Add(new() + FashionList fashion = new() { Id = character.DefaultNpcFashtionId, IsLock = false - }); + }; + Fashions.Add(fashion); + ret.Fashion = fashion; if (character.EquipId > 0) - AddEquip((uint)character.EquipId, character.Id); + ret.Equip = AddEquip((uint)character.EquipId, character.Id); Characters.Add(characterData); + ret.Character = characterData; + return ret; } public NotifyCharacterDataList.NotifyCharacterDataListCharacterData? AddCharacterExp(int characterId, int exp, int maxLvl = 0) @@ -167,7 +185,7 @@ namespace AscNet.Common.Database }; } - public void AddEquip(uint equipId, int characterId = 0) + public NotifyEquipDataList.NotifyEquipDataListEquipData AddEquip(uint equipId, int characterId = 0) { NotifyEquipDataList.NotifyEquipDataListEquipData equipData = new() { @@ -186,6 +204,7 @@ namespace AscNet.Common.Database }; Equips.Add(equipData); + return equipData; } public NotifyEquipDataList.NotifyEquipDataListEquipData? AddEquipExp(int equipId, int exp) @@ -282,4 +301,11 @@ namespace AscNet.Common.Database [JsonProperty("TemplateId")] public int TemplateId { get; set; } } + + public struct AddCharacterRet + { + public NotifyCharacterDataList.NotifyCharacterDataListCharacterData Character { get; set; } + public NotifyEquipDataList.NotifyEquipDataListEquipData Equip { get; set; } + public FashionList Fashion { get; set; } + } } diff --git a/AscNet.Common/MsgPack/Types.cs b/AscNet.Common/MsgPack/Types.cs index 038533c..b75561f 100644 --- a/AscNet.Common/MsgPack/Types.cs +++ b/AscNet.Common/MsgPack/Types.cs @@ -32,7 +32,7 @@ namespace AscNet.Common.MsgPack public String ServerBean { get; set; } public Int32 LoginPlatform { get; set; } public String ClientVersion { get; set; } - public Int32 UserId { get; set; } + public dynamic UserId { get; set; } } @@ -2360,6 +2360,13 @@ namespace AscNet.Common.MsgPack } + [global::MessagePack.MessagePackObject(true)] + public class EnterChallengeResponse + { + public Int32 Code { get; set; } + } + + [global::MessagePack.MessagePackObject(true)] public class TeamSetTeamResponse { diff --git a/AscNet.GameServer/Handlers/CharacterModule.cs b/AscNet.GameServer/Handlers/CharacterModule.cs index bf87f26..e9621ee 100644 --- a/AscNet.GameServer/Handlers/CharacterModule.cs +++ b/AscNet.GameServer/Handlers/CharacterModule.cs @@ -22,11 +22,85 @@ namespace AscNet.GameServer.Handlers { public int Code; } + + [MessagePackObject(true)] + public class CharacterExchangeRequest + { + public int TemplateId; + } + + [MessagePackObject(true)] + public class CharacterExchangeResponse + { + public int Code; + } + + [MessagePackObject(true)] + public class FashionSyncNotify + { + public List FashionList = new(); + } #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. #endregion internal class CharacterModule { + [RequestPacketHandler("CharacterExchangeRequest")] + public static void CharacterExchangeRequestHandler(Session session, Packet.Request packet) + { + CharacterExchangeRequest request = packet.Deserialize(); + CharacterTable? characterData = TableReaderV2.Parse().FirstOrDefault(x => x.Id == request.TemplateId); + + if (characterData is null) + { + CharacterExchangeResponse rsp = new() + { + // CharacterManagerGetCharacterTemplateNotFound + Code = 20009001 + }; + session.SendResponse(rsp, packet.Id); + return; + } + + if (!session.inventory.Items.Any(x => x.Id == characterData.ItemId && x.Count >= 50)) + { + CharacterExchangeResponse rsp = new() + { + // ItemCountNotEnough + Code = 20012004 + }; + session.SendResponse(rsp, packet.Id); + return; + } + + NotifyItemDataList notifyItemData = new(); + // idk if it's always 50, please investigate later... + notifyItemData.ItemDataList.Add(session.inventory.Do(characterData.ItemId, 50 * -1)); + session.SendPush(notifyItemData); + + try + { + NotifyEquipDataList notifyEquipData = new(); + FashionSyncNotify fashionSync = new(); + NotifyCharacterDataList notifyCharacterData = new(); + var addRet = session.character.AddCharacter((uint)request.TemplateId); + + notifyEquipData.EquipDataList.Add(addRet.Equip); + fashionSync.FashionList.Add(addRet.Fashion); + notifyCharacterData.CharacterDataList.Add(addRet.Character); + session.SendPush(notifyEquipData); + session.SendPush(notifyCharacterData); + } + catch (ServerCodeException ex) + { + CharacterExchangeResponse rsp = new() { Code = ex.Code }; + session.SendResponse(rsp, packet.Id); + return; + } + + session.SendResponse(new CharacterExchangeResponse(), packet.Id); + } + [RequestPacketHandler("CharacterUpgradeSkillGroupRequest")] public static void CharacterUpgradeSkillGroupRequestHandler(Session session, Packet.Request packet) { diff --git a/AscNet.GameServer/Handlers/FightModule.cs b/AscNet.GameServer/Handlers/FightModule.cs index b51e011..ee97001 100644 --- a/AscNet.GameServer/Handlers/FightModule.cs +++ b/AscNet.GameServer/Handlers/FightModule.cs @@ -194,6 +194,12 @@ namespace AscNet.GameServer.Handlers session.SendResponse(new TeamSetTeamResponse(), packet.Id); } + [RequestPacketHandler("EnterChallengeRequest")] + public static void HandleEnterChallengeRequestHandler(Session session, Packet.Request packet) + { + session.SendResponse(new EnterChallengeResponse(), packet.Id); + } + [RequestPacketHandler("FightSettleRequest")] public static void FightSettleRequestHandler(Session session, Packet.Request packet) { diff --git a/AscNet.GameServer/Handlers/ItemModule.cs b/AscNet.GameServer/Handlers/ItemModule.cs new file mode 100644 index 0000000..617153c --- /dev/null +++ b/AscNet.GameServer/Handlers/ItemModule.cs @@ -0,0 +1,35 @@ +using MessagePack; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AscNet.GameServer.Handlers +{ + #region MsgPackScheme +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + [MessagePackObject(true)] + public class GetAndroidOrIosMoneyCardResponse + { + public int Code; + public int MoneyCard; + public int Count; + } +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + #endregion + + internal class ItemModule + { + [RequestPacketHandler("GetAndroidOrIosMoneyCardRequest")] + public static void GetAndroidOrIosMoneyCardRequestHandler(Session session, Packet.Request packet) + { + session.SendResponse(new GetAndroidOrIosMoneyCardResponse() + { + Code = 0, + Count = 0, + MoneyCard = 0 + }, packet.Id); + } + } +} diff --git a/AscNet.GameServer/Handlers/PlayerModule.cs b/AscNet.GameServer/Handlers/PlayerModule.cs index 40a3b0d..ec40a07 100644 --- a/AscNet.GameServer/Handlers/PlayerModule.cs +++ b/AscNet.GameServer/Handlers/PlayerModule.cs @@ -18,6 +18,17 @@ namespace AscNet.GameServer.Handlers public int Code; } + [MessagePackObject(true)] + public class TouchBoardMutualRequest + { + public int CharacterId; + } + + [MessagePackObject(true)] + public class TouchBoardMutualResponse + { + } + [MessagePackObject(true)] public class ChangeCommunicationRequest { @@ -51,5 +62,13 @@ namespace AscNet.GameServer.Handlers session.SendResponse(new ChangeCommunicationResponse(), packet.Id); } + + [RequestPacketHandler("TouchBoardMutualRequest")] + public static void TouchBoardMutualRequestHandler(Session session, Packet.Request packet) + { + TouchBoardMutualRequest request = MessagePackSerializer.Deserialize(packet.Content); + + session.SendResponse(new TouchBoardMutualResponse(), packet.Id); + } } } diff --git a/AscNet.SDKServer/Controllers/AccountController.cs b/AscNet.SDKServer/Controllers/AccountController.cs index bea5afa..d5ad8d4 100644 --- a/AscNet.SDKServer/Controllers/AccountController.cs +++ b/AscNet.SDKServer/Controllers/AccountController.cs @@ -108,7 +108,7 @@ namespace AscNet.SDKServer.Controllers }); }); - app.MapGet("/api/Login/Login", ([FromQuery] int loginType, [FromQuery] int userId, [FromQuery] string token, [FromQuery] string clientIp) => + app.MapGet("/api/Login/Login", ([FromQuery] int loginType, [FromQuery] int userId, [FromQuery] string token, [FromQuery] string? clientIp) => { Account? account = Account.FromToken(token); diff --git a/AscNet.SDKServer/Controllers/ConfigController.cs b/AscNet.SDKServer/Controllers/ConfigController.cs index e54a0a8..081197b 100644 --- a/AscNet.SDKServer/Controllers/ConfigController.cs +++ b/AscNet.SDKServer/Controllers/ConfigController.cs @@ -16,7 +16,7 @@ namespace AscNet.SDKServer.Controllers public static void Register(WebApplication app) { - app.MapGet("/prod/client/config/com.kurogame.punishing.grayraven.en.pc/{version}/standalone/config.tab", (HttpContext ctx) => + app.MapGet("/prod/client/config/{package}/{version}/standalone/config.tab", (HttpContext ctx) => { List remoteConfigs = new(); ServerVersionConfig versionConfig = versions.GetValueOrDefault((string)ctx.Request.RouteValues["version"]!) ?? versions.First().Value; @@ -27,11 +27,21 @@ namespace AscNet.SDKServer.Controllers remoteConfigs.AddConfig("ApplicationVersion", (string)ctx.Request.RouteValues["version"]!); remoteConfigs.AddConfig("Debug", true); remoteConfigs.AddConfig("External", true); - remoteConfigs.AddConfig("Channel", 1); remoteConfigs.AddConfig("PayCallbackUrl", "empty"); - remoteConfigs.AddConfig("PrimaryCdns", "http://prod-encdn-akamai.kurogame.net/prod|http://prod-encdn-aliyun.kurogame.net/prod"); - remoteConfigs.AddConfig("SecondaryCdns", "http://prod-encdn-aliyun.kurogame.net/prod"); - remoteConfigs.AddConfig("CdnInvalidTime", 600); + switch ((string?)ctx.Request.RouteValues["package"]) + { + case "com.kurogame.haru.kuro": + remoteConfigs.AddConfig("PrimaryCdns", "http://prod-zspnsalicdn.kurogame.com/prod"); + remoteConfigs.AddConfig("SecondaryCdns", "http://prod-zspnstxcdn.kurogame.com/prod"); + remoteConfigs.AddConfig("Channel", 2); + break; + default: + remoteConfigs.AddConfig("PrimaryCdns", "http://prod-encdn-akamai.kurogame.net/prod|http://prod-encdn-aliyun.kurogame.net/prod"); + remoteConfigs.AddConfig("SecondaryCdns", "http://prod-encdn-aliyun.kurogame.net/prod"); + remoteConfigs.AddConfig("Channel", 1); + break; + } + remoteConfigs.AddConfig("CdnInvalidTime", 60); remoteConfigs.AddConfig("MtpEnabled", false); remoteConfigs.AddConfig("MemoryLimit", 2048); remoteConfigs.AddConfig("CloseMsgEncrypt", false); @@ -44,12 +54,16 @@ namespace AscNet.SDKServer.Controllers remoteConfigs.AddConfig("DownloadMethod", 1); remoteConfigs.AddConfig("PcPayCallbackList", $"{Common.Common.config.GameServer.Host}/api/XPay/KuroPayResult"); + // 2.9.0 + remoteConfigs.AddConfig("WatermarkType", 2); + remoteConfigs.AddConfig("ChannelServerListStr", $"1#{Common.Common.config.GameServer.RegionName}#{Common.Common.config.GameServer.Host}/api/Login/Login"); + string serializedObject = TsvTool.SerializeObject(remoteConfigs); SDKServer.log.Info(serializedObject); return serializedObject; }); - app.MapGet("/prod/client/notice/config/com.kurogame.punishing.grayraven.en.pc/{version}/LoginNotice.json", (HttpContext ctx) => + app.MapGet("/prod/client/notice/config/{package}/{version}/LoginNotice.json", (HttpContext ctx) => { LoginNotice notice = new() { @@ -66,7 +80,7 @@ namespace AscNet.SDKServer.Controllers return serializedObject; }); - app.MapGet("/prod/client/notice/config/com.kurogame.punishing.grayraven.en.pc/{version}/ScrollTextNotice.json", (HttpContext ctx) => + app.MapGet("/prod/client/notice/config/{package}/{version}/ScrollTextNotice.json", (HttpContext ctx) => { ScrollTextNotice notice = new() { @@ -86,7 +100,7 @@ namespace AscNet.SDKServer.Controllers return serializedObject; }); - app.MapGet("/prod/client/notice/config/com.kurogame.punishing.grayraven.en.pc/{version}/ScrollPicNotice.json", (HttpContext ctx) => + app.MapGet("/prod/client/notice/config/{package}/{version}/ScrollPicNotice.json", (HttpContext ctx) => { ScrollPicNotice notice = new() { @@ -117,7 +131,7 @@ namespace AscNet.SDKServer.Controllers return serializedObject; }); - app.MapGet("/prod/client/notice/config/com.kurogame.punishing.grayraven.en.pc/{version}/GameNotice.json", (HttpContext ctx) => + app.MapGet("/prod/client/notice/config/{package}/{version}/GameNotice.json", (HttpContext ctx) => { List notices = new(); diff --git a/AscNet.SDKServer/SDKServer.cs b/AscNet.SDKServer/SDKServer.cs index ca4cb3a..115d8e3 100644 --- a/AscNet.SDKServer/SDKServer.cs +++ b/AscNet.SDKServer/SDKServer.cs @@ -56,7 +56,11 @@ namespace AscNet.SDKServer } catch (Exception ex) { +#if DEBUG + log.Error($"{ex} Request below:"); +#else log.Error($"{ex.Message} Request below:"); +#endif } finally { diff --git a/Resources/Configs/version_config.json b/Resources/Configs/version_config.json index cd3c8c5..0477260 100644 --- a/Resources/Configs/version_config.json +++ b/Resources/Configs/version_config.json @@ -12,5 +12,12 @@ "IndexMd5": "c5d4baac85a6e37b8109ea43dc045d31", "IndexSha1": "5e1c9a7213857d9f1c1223f4871feb425a598294", "LaunchIndexSha1": "def7cf0ae2dbc6a31c5f85632f1d82d1f1d6cbfa" + }, + "2.9.0": { + "DocumentVersion": "2.9.15", + "LaunchModuleVersion": "2.9.15", + "IndexMd5": "c5d4baac85a6e37b8109ea43dc045d31", + "IndexSha1": "ee9b1d7242fe7ff9621f3b7451c969b06b8f7638", + "LaunchIndexSha1": "7e0de243ba0074fe2e5c194d686c693e29f65b92" } } \ No newline at end of file