From e81893c8f2b90fa383fbc82285124f5ca5809ec8 Mon Sep 17 00:00:00 2001 From: Mikhail Thompson Date: Sun, 30 Jun 2024 12:24:36 -0400 Subject: [PATCH] commit code from airplane --- README.md | 3 +- nksrv/LobbyServer/LobbyHandler.cs | 42 +++++ .../Msgs/Campaign/GetCampaignField.cs | 2 +- .../Character/GetCharacterAttractiveList.cs | 2 +- nksrv/LobbyServer/Msgs/Gacha/ExecGacha.cs | 3 + .../Msgs/Shop/GetShopProductList.cs | 21 +++ nksrv/LobbyServer/Msgs/Stage/ClearStage.cs | 152 +++++++++++------- nksrv/LobbyServer/Msgs/Team/GetTeamData.cs | 16 +- nksrv/LobbyServer/Msgs/Team/SetTeam.cs | 15 +- .../LobbyServer/Msgs/User/EnterLobbyServer.cs | 55 ++----- .../LobbyServer/Msgs/User/GetProfileFrame.cs | 2 +- nksrv/LobbyServer/Msgs/User/GetUser.cs | 13 +- nksrv/LobbyServer/Msgs/User/GetUserProfile.cs | 4 +- nksrv/LobbyServer/Msgs/Wallet/GetWallet.cs | 7 + nksrv/Program.cs | 7 +- nksrv/Protos/allmsgs.proto | 9 ++ nksrv/StaticInfo/JsonStaticData.cs | 19 +++ nksrv/StaticInfo/StaticDataParser.cs | 63 +++++++- nksrv/Utils/JsonDb.cs | 25 +-- nksrv/Utils/PacketDecryption.cs | 2 - 20 files changed, 317 insertions(+), 145 deletions(-) create mode 100644 nksrv/LobbyServer/Msgs/Shop/GetShopProductList.cs diff --git a/README.md b/README.md index 906f024..b86ca81 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,8 @@ NOTE: Make sure to undo these modifications (especially change back sodium.dll) After doing the following steps, you can register an account in the launcher (enter anything into email verification code section), and play like normal. ## Progress -Stage, character, and story information is saved, as well as player nickname. Lobby UI kind of works. Nothing else works though, such as rewards. +Stage, character, and story information is saved and works, as well as player nickname. +TODO: Gacha system, reward system, xp system, sim room, outpost, etc TODO: Provide screenshots diff --git a/nksrv/LobbyServer/LobbyHandler.cs b/nksrv/LobbyServer/LobbyHandler.cs index f37fbec..31a02b3 100644 --- a/nksrv/LobbyServer/LobbyHandler.cs +++ b/nksrv/LobbyServer/LobbyHandler.cs @@ -3,6 +3,7 @@ using EmbedIO; using Google.Protobuf; using nksrv.Utils; using Swan.Logging; +using static Google.Rpc.Context.AttributeContext.Types; namespace nksrv.LobbyServer { @@ -105,6 +106,47 @@ namespace nksrv.LobbyServer { // By calling this function, we force .NET to initialize handler dictanary to catch errors early on. } + + public static NetUserData CreateNetUserDataFromUser(User user) + { + NetUserData ret = new() + { + Lv = 1, + CommanderRoomJukebox = 5, + CostumeLv = 1, + Frame = 1, + Icon = user.ProfileIconId, + IconPrism = user.ProfileIconIsPrism, + LobbyJukebox = 2, + InfraCoreExp = user.InfraCoreExp, + InfraCoreLv = user.InfraCoreLvl, + }; + + + // Restore completed tutorials. GroupID is the first 4 digits of the Table ID. + foreach (var item in user.ClearedTutorials) + { + var groupId = int.Parse(item.ToString().Substring(0, 4)); + int tutorialVersion = item == 1020101 ? 1 : 0; // TODO: Read from static data + ret.Tutorials.Add(new NetTutorialData() { GroupId = groupId, LastClearedTid = item, LastClearedVersion = tutorialVersion }); + } + + return ret; + } + public static NetWholeUserData CreateWholeUserDataFromDbUser(User user) + { + var ret = new NetWholeUserData() + { + Lv = 1, + Frame = 1, + Icon = user.ProfileIconId, + IconPrism = user.ProfileIconIsPrism, + Nickname = user.Nickname, + Usn = (long)user.ID + }; + + return ret; + } } public class GameClientInfo diff --git a/nksrv/LobbyServer/Msgs/Campaign/GetCampaignField.cs b/nksrv/LobbyServer/Msgs/Campaign/GetCampaignField.cs index 0c6bce0..070b784 100644 --- a/nksrv/LobbyServer/Msgs/Campaign/GetCampaignField.cs +++ b/nksrv/LobbyServer/Msgs/Campaign/GetCampaignField.cs @@ -24,7 +24,7 @@ namespace nksrv.LobbyServer.Msgs.Campaign // todo save this data response.Team = new NetUserTeamData() { LastContentsTeamNumber = 1, Type = 1 }; - if (user.LastStageCleared >= 6000003) + if (user.LastNormalStageCleared >= 6000003) { var team = new NetTeamData() { TeamNumber = 1 }; team.Slots.Add(new NetTeamSlot() { Slot = 1, Value = 47263455 }); diff --git a/nksrv/LobbyServer/Msgs/Character/GetCharacterAttractiveList.cs b/nksrv/LobbyServer/Msgs/Character/GetCharacterAttractiveList.cs index a34cd75..ab8d6b1 100644 --- a/nksrv/LobbyServer/Msgs/Character/GetCharacterAttractiveList.cs +++ b/nksrv/LobbyServer/Msgs/Character/GetCharacterAttractiveList.cs @@ -16,7 +16,7 @@ namespace nksrv.LobbyServer.Msgs.Character var response = new ResGetAttractiveList(); response.CounselAvailableCount = 3; // TODO - + // TODO: Validate response from real server and pull info from user info WriteData(response); } diff --git a/nksrv/LobbyServer/Msgs/Gacha/ExecGacha.cs b/nksrv/LobbyServer/Msgs/Gacha/ExecGacha.cs index e76d59a..af5bf00 100644 --- a/nksrv/LobbyServer/Msgs/Gacha/ExecGacha.cs +++ b/nksrv/LobbyServer/Msgs/Gacha/ExecGacha.cs @@ -16,6 +16,9 @@ namespace nksrv.LobbyServer.Msgs.Gacha var response = new ResExecuteGacha(); + // TODO: Pick random character that player does not have unless it supports limit break. + // TODO: Write character to user info. + // TODO implement response.Reward = new NetRewardData(); for (int i = 0; i < 10; i++) diff --git a/nksrv/LobbyServer/Msgs/Shop/GetShopProductList.cs b/nksrv/LobbyServer/Msgs/Shop/GetShopProductList.cs new file mode 100644 index 0000000..b5cf93b --- /dev/null +++ b/nksrv/LobbyServer/Msgs/Shop/GetShopProductList.cs @@ -0,0 +1,21 @@ +using nksrv.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace nksrv.LobbyServer.Msgs.Shop +{ + [PacketPath("/shop/productlist")] + public class GetShopProductList : LobbyMsgHandler + { + protected override async Task HandleAsync() + { + var req = await ReadData(); + var response = new ResShopProductList(); + + WriteData(response); + } + } +} diff --git a/nksrv/LobbyServer/Msgs/Stage/ClearStage.cs b/nksrv/LobbyServer/Msgs/Stage/ClearStage.cs index 429fcbc..a8670d0 100644 --- a/nksrv/LobbyServer/Msgs/Stage/ClearStage.cs +++ b/nksrv/LobbyServer/Msgs/Stage/ClearStage.cs @@ -27,7 +27,7 @@ namespace nksrv.LobbyServer.Msgs.Stage var clearedStage = StaticDataParser.Instance.GetStageData(req.StageId); if (clearedStage == null) throw new Exception("cleared stage cannot be null"); - user.LastStageCleared = req.StageId; + user.LastNormalStageCleared = req.StageId; if (user.FieldInfo.Count == 0) { @@ -35,59 +35,86 @@ namespace nksrv.LobbyServer.Msgs.Stage } DoQuestSpecificUserOperations(user, req.StageId); + var rewardData = StaticDataParser.Instance.GetRewardTableEntry(clearedStage.reward_id); - // TODO: figure out how stageid corresponds to chapter user.FieldInfo[clearedStage.chapter_id - 1].CompletedStages.Add(new NetFieldStageData() { StageId = req.StageId }); - JsonDb.Save(); - - - - // assign rewards - if (StageCompletionReward.RewardData.ContainsKey(req.StageId)) - { - var reward = StageCompletionReward.RewardData[req.StageId]; - - Dictionary current = new Dictionary(); - - // add all currencies that users has to current dictionary - foreach (var currentReward in user.Currency) - { - if (!current.ContainsKey(currentReward.Key)) - current.Add(currentReward.Key, 0); - - current[currentReward.Key] = (int)currentReward.Value; - } - - - // add currency reward to response - response.StageClearReward = new NetRewardData(); - foreach (var item in reward.Currency) - { - if (!current.ContainsKey((CurrencyType)item.Type)) - current.Add((CurrencyType)item.Type, 0); - var val = current[(CurrencyType)item.Type]; - response.StageClearReward.Currency.Add(new NetCurrencyData() { Type = item.Type, Value = item.Value, FinalValue = val + item.Value }); - } - - // add currency reward to user info - foreach (var item in reward.Currency) - { - if (!user.Currency.ContainsKey((CurrencyType)item.Type)) - user.Currency.Add((CurrencyType)item.Type, item.Value); - else - user.Currency[(CurrencyType)item.Type] += item.Value; - } - JsonDb.Save(); - } + if (rewardData != null) + response.Reward = RegisterRewardsForUser(user, rewardData); else - { - Logger.Warn("TODO - Reward for stage ID " + req.StageId); - } + Logger.Warn("rewardId is null for stage " + req.StageId); + JsonDb.Save(); } WriteData(response); } + private NetRewardData RegisterRewardsForUser(Utils.User user, RewardTableRecord rewardData) + { + NetRewardData ret = new(); + if (rewardData.rewards == null) return ret; + + if (rewardData.user_exp != 0) + { + var newXp = rewardData.character_exp + user.userPointData.ExperiencePoint; + var newLevel = StaticDataParser.Instance.GetUserLevelFromUserExp(newXp); + if (newLevel == -1) + { + Logger.Warn("Unknown user level value for xp " + newXp); + } + //ret.UserExp = new NetIncreaseExpData() + //{ + // BeforeExp = user.userPointData.ExperiencePoint, + // BeforeLv = user.userPointData.UserLevel, + // IncreaseExp = rewardData.character_exp, + // CurrentExp = rewardData.character_exp + newXp, + // CurrentLv = newLevel, + // GainExp = rewardData.character_exp + //}; + user.userPointData.ExperiencePoint += rewardData.character_exp; + } + + foreach (var item in rewardData.rewards) + { + if (item.reward_id != 0) + { + if (item.reward_type == "Currency") + { + Dictionary current = new Dictionary(); + + // add all currencies that users has to current dictionary + foreach (var currentReward in user.Currency) + { + if (!current.ContainsKey(currentReward.Key)) + current.Add(currentReward.Key, 0); + + current[currentReward.Key] = (int)currentReward.Value; + } + + // add currency reward to response + CurrencyType t = (CurrencyType)item.reward_id; + int val = item.reward_value; + if (!current.ContainsKey(t)) + current.Add(t, 0); + var val2 = current[t]; + ret.Currency.Add(new NetCurrencyData() { Type = (int)t, Value = val, FinalValue = val2 + val }); + + + // add currency reward to user info + if (!user.Currency.ContainsKey(t)) + user.Currency.Add(t, val); + else + user.Currency[t] += val; + } + } + else + { + Logger.Warn("TODO: Reward type " + item.reward_type); + } + } + + return ret; + } + private static void DoQuestSpecificUserOperations(Utils.User user, int clearedStageId) { var quest = StaticDataParser.Instance.GetMainQuestForStageClearCondition(clearedStageId); @@ -99,21 +126,38 @@ namespace nksrv.LobbyServer.Msgs.Stage // TODO: Is this the right place to copy over default characters? // TODO: What is CSN and TID? Also need to add names for these // Note: TID is table index, not sure what CSN is + + // create a squad with first 5 characters + var team1 = new NetUserTeamData(); + team1.Type = 1; + team1.LastContentsTeamNumber = 1; + + var team1Sub = new NetTeamData(); + team1Sub.TeamNumber = 1; + for (int i = 1; i < 6; i++) + { + var character = user.Characters[i - 1]; + team1Sub.Slots.Add(new NetTeamSlot() { Slot = i, Value = character.Csn }); + } + team1.Teams.Add(team1Sub); + user.UserTeams.Add(1, team1); + user.Characters.Add(new Utils.Character() { Csn = 47263455, Tid = 201001 }); user.Characters.Add(new Utils.Character() { Csn = 47273456, Tid = 330501 }); user.Characters.Add(new Utils.Character() { Csn = 47263457, Tid = 130201 }); user.Characters.Add(new Utils.Character() { Csn = 47263458, Tid = 230101 }); user.Characters.Add(new Utils.Character() { Csn = 47263459, Tid = 301201 }); - user.TeamData.TeamNumber = 1; - user.TeamData.TeamCombat = 1446; // TODO: Don't hardcode this - user.TeamData.Slots.Clear(); - user.TeamData.Slots.Add(new NetWholeTeamSlot { Slot = 1, Csn = 47263455, Tid = 201001, Lvl = 1 }); - user.TeamData.Slots.Add(new NetWholeTeamSlot { Slot = 2, Csn = 47273456, Tid = 330501, Lvl = 1 }); - user.TeamData.Slots.Add(new NetWholeTeamSlot { Slot = 3, Csn = 47263457, Tid = 130201, Lvl = 1 }); - user.TeamData.Slots.Add(new NetWholeTeamSlot { Slot = 4, Csn = 47263458, Tid = 230101, Lvl = 1 }); - user.TeamData.Slots.Add(new NetWholeTeamSlot { Slot = 5, Csn = 47263459, Tid = 301201, Lvl = 1 }); + user.RepresentationTeamData.TeamNumber = 1; + user.RepresentationTeamData.TeamCombat = 1446; // TODO: Don't hardcode this + user.RepresentationTeamData.Slots.Clear(); + user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot { Slot = 1, Csn = 47263455, Tid = 201001, Lvl = 1 }); + user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot { Slot = 2, Csn = 47273456, Tid = 330501, Lvl = 1 }); + user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot { Slot = 3, Csn = 47263457, Tid = 130201, Lvl = 1 }); + user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot { Slot = 4, Csn = 47263458, Tid = 230101, Lvl = 1 }); + user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot { Slot = 5, Csn = 47263459, Tid = 301201, Lvl = 1 }); } + // TODO: add neon } } } diff --git a/nksrv/LobbyServer/Msgs/Team/GetTeamData.cs b/nksrv/LobbyServer/Msgs/Team/GetTeamData.cs index 5018fa6..c099db7 100644 --- a/nksrv/LobbyServer/Msgs/Team/GetTeamData.cs +++ b/nksrv/LobbyServer/Msgs/Team/GetTeamData.cs @@ -21,22 +21,10 @@ namespace nksrv.LobbyServer.Msgs.Team // NOTE: Keep this in sync with EnterLobbyServer code if (user.Characters.Count > 0) { - var team1 = new NetUserTeamData(); - team1.Type = 1; - team1.LastContentsTeamNumber = 1; - - var team1Sub = new NetTeamData(); - team1Sub.TeamNumber = 1; - - // TODO: Save this properly. Right now return first 5 characters as a squad. - for (int i = 1; i < 6; i++) + foreach (var item in user.UserTeams) { - var character = user.Characters[i - 1]; - team1Sub.Slots.Add(new NetTeamSlot() { Slot = i, Value = character.Csn }); + response.TypeTeams.Add(item.Value); } - team1.Teams.Add(team1Sub); - - response.TypeTeams.Add(team1); } WriteData(response); } diff --git a/nksrv/LobbyServer/Msgs/Team/SetTeam.cs b/nksrv/LobbyServer/Msgs/Team/SetTeam.cs index c970e82..ae13000 100644 --- a/nksrv/LobbyServer/Msgs/Team/SetTeam.cs +++ b/nksrv/LobbyServer/Msgs/Team/SetTeam.cs @@ -15,11 +15,24 @@ namespace nksrv.LobbyServer.Msgs.Team var req = await ReadData(); var user = GetUser(); + // TODO is this right var response = new ResSetTeam(); response.Type = req.Type; response.Teams.AddRange(req.Teams.ToArray()); - // TODO + // Add team data to user data + var teamData = new NetUserTeamData() { LastContentsTeamNumber = req.ContentsId, Type = req.Type }; + teamData.Teams.AddRange(req.Teams); + + if (user.UserTeams.ContainsKey(req.Type)) + { + user.UserTeams[req.Type] = teamData; + } + else + { + user.UserTeams.Add(req.Type, teamData); + } + JsonDb.Save(); WriteData(response); } diff --git a/nksrv/LobbyServer/Msgs/User/EnterLobbyServer.cs b/nksrv/LobbyServer/Msgs/User/EnterLobbyServer.cs index 0ed4e2b..f09b272 100644 --- a/nksrv/LobbyServer/Msgs/User/EnterLobbyServer.cs +++ b/nksrv/LobbyServer/Msgs/User/EnterLobbyServer.cs @@ -18,31 +18,25 @@ namespace nksrv.LobbyServer.Msgs.User // NOTE: Keep this in sync with GetUser code var response = new ResEnterLobbyServer(); - response.User = new NetUserData(); - response.User.Lv = 1; - response.User.CommanderRoomJukebox = 5; - response.User.CostumeLv = 1; - response.User.Frame = 1; - response.User.Icon = user.ProfileIconId; - response.User.IconPrism = user.ProfileIconIsPrism; - response.User.LobbyJukebox = 2; + response.User = LobbyHandler.CreateNetUserDataFromUser(user); response.ResetHour = 20; response.Nickname = user.Nickname; response.SynchroLv = 1; response.OutpostBattleLevel = new NetOutpostBattleLevel() { Level = 1 }; response.OutpostBattleTime = new NetOutpostBattleTime() { MaxBattleTime = 864000000000, MaxOverBattleTime = 12096000000000 }; - if (user.TeamData.Slots.Count == 0) + // Add default slot data + if (user.RepresentationTeamData.Slots.Count == 0) { - user.TeamData = new NetWholeUserTeamData() { TeamNumber = 1, Type = 2 }; - user.TeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 1 }); - user.TeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 2 }); - user.TeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 3 }); - user.TeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 4 }); - user.TeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 5 }); + user.RepresentationTeamData = new NetWholeUserTeamData() { TeamNumber = 1, Type = 2 }; + user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 1 }); + user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 2 }); + user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 3 }); + user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 4 }); + user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 5 }); JsonDb.Save(); } - response.RepresentationTeam = user.TeamData; + response.RepresentationTeam = user.RepresentationTeamData; foreach (var item in user.Currency) { @@ -53,24 +47,11 @@ namespace nksrv.LobbyServer.Msgs.User response.Character.Add(new NetUserCharacterData() { Default = new() { Csn = item.Csn, Skill1Lv = item.Skill1Lvl, Skill2Lv = item.Skill2Lvl, CostumeId = item.CostumeId, Lv = item.Level, Grade = item.Grade, Tid = item.Tid, UltiSkillLv = item.UltimateLevel } }); } + // Add squad data if there are characters if (user.Characters.Count > 0) { - var team1 = new NetUserTeamData(); - team1.Type = 1; - team1.LastContentsTeamNumber = 1; - - var team1Sub = new NetTeamData(); - team1Sub.TeamNumber = 1; - - // TODO: Save this properly. Right now return first 5 characters as a squad. - for (int i = 1; i < 6; i++) - { - var character = user.Characters[i - 1]; - team1Sub.Slots.Add(new NetTeamSlot() { Slot = i, Value = character.Csn }); - } - team1.Teams.Add(team1Sub); - - response.TypeTeams.Add(team1); + foreach (var teamInfo in user.UserTeams) + response.TypeTeams.Add(teamInfo.Value); } // TODO: Save outpost data @@ -86,15 +67,7 @@ namespace nksrv.LobbyServer.Msgs.User response.Outposts.Add(new NetUserOutpostData() { SlotId = 10, BuildingId = 23501, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 }); response.Outposts.Add(new NetUserOutpostData() { SlotId = 38, BuildingId = 33601, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 }); - response.LastClearedNormalMainStageId = user.LastStageCleared; - - // Restore completed tutorials. GroupID is the first 4 digits of the Table ID. - foreach (var item in user.ClearedTutorials) - { - var groupId = int.Parse(item.ToString().Substring(0, 4)); - int tutorialVersion = item == 1020101 ? 1 : 0; // TODO - response.User.Tutorials.Add(new NetTutorialData() { GroupId = groupId, LastClearedTid = item, LastClearedVersion = tutorialVersion }); - } + response.LastClearedNormalMainStageId = user.LastNormalStageCleared; WriteData(response); } diff --git a/nksrv/LobbyServer/Msgs/User/GetProfileFrame.cs b/nksrv/LobbyServer/Msgs/User/GetProfileFrame.cs index 847d888..78223e4 100644 --- a/nksrv/LobbyServer/Msgs/User/GetProfileFrame.cs +++ b/nksrv/LobbyServer/Msgs/User/GetProfileFrame.cs @@ -15,7 +15,7 @@ namespace nksrv.LobbyServer.Msgs.User var req = await ReadData(); var response = new ResGetProfileFrame(); - + WriteData(response); } } diff --git a/nksrv/LobbyServer/Msgs/User/GetUser.cs b/nksrv/LobbyServer/Msgs/User/GetUser.cs index a1fb61d..f096c20 100644 --- a/nksrv/LobbyServer/Msgs/User/GetUser.cs +++ b/nksrv/LobbyServer/Msgs/User/GetUser.cs @@ -19,14 +19,7 @@ namespace nksrv.LobbyServer.Msgs.User var user = GetUser(); - response.User = new NetUserData(); - response.User.Lv = 1; - response.User.CommanderRoomJukebox = 5; - response.User.CostumeLv = 1; - response.User.Frame = 1; - response.User.Icon = user.ProfileIconId; - response.User.IconPrism = user.ProfileIconIsPrism; - response.User.LobbyJukebox = 2; + response.User = LobbyHandler.CreateNetUserDataFromUser(user); response.ResetHour = 20; response.OutpostBattleTime = new NetOutpostBattleTime() { MaxBattleTime = 864000000000, MaxOverBattleTime = 12096000000000 }; response.IsSimple = req.IsSimple; @@ -35,9 +28,9 @@ namespace nksrv.LobbyServer.Msgs.User { response.Currency.Add(new NetUserCurrencyData() { Type = (int)item.Key, Value = item.Value }); } - response.RepresentationTeam = user.TeamData; + response.RepresentationTeam = user.RepresentationTeamData; - response.LastClearedNormalMainStageId = user.LastStageCleared; + response.LastClearedNormalMainStageId = user.LastNormalStageCleared; // Restore completed tutorials. GroupID is the first 4 digits of the Table ID. foreach (var item in user.ClearedTutorials) diff --git a/nksrv/LobbyServer/Msgs/User/GetUserProfile.cs b/nksrv/LobbyServer/Msgs/User/GetUserProfile.cs index 2454e25..dd3bceb 100644 --- a/nksrv/LobbyServer/Msgs/User/GetUserProfile.cs +++ b/nksrv/LobbyServer/Msgs/User/GetUserProfile.cs @@ -20,9 +20,7 @@ namespace nksrv.LobbyServer.Msgs.User Console.WriteLine("GET USER PROFILE NOT IMPLEMENTED: " + req.TargetUsn); if (user.ID == (ulong)req.TargetUsn) { - response.Data.User = new NetWholeUserData(); - response.Data.User.Icon = user.ProfileIconId; - response.Data.User.IconPrism = user.ProfileIconIsPrism; + response.Data.User = LobbyHandler.CreateWholeUserDataFromDbUser(user); } else { diff --git a/nksrv/LobbyServer/Msgs/Wallet/GetWallet.cs b/nksrv/LobbyServer/Msgs/Wallet/GetWallet.cs index ea9fff0..ae99c9b 100644 --- a/nksrv/LobbyServer/Msgs/Wallet/GetWallet.cs +++ b/nksrv/LobbyServer/Msgs/Wallet/GetWallet.cs @@ -13,11 +13,18 @@ namespace nksrv.LobbyServer.Msgs.Wallet protected override async Task HandleAsync() { var req = await ReadData(); + var user = GetUser(); + var response = new ResGetCurrencyData(); foreach (var item in req.Currencies) { Console.WriteLine("Request currency " + (CurrencyType)item); } + + foreach (var currency in user.Currency) + { + response.Currency.Add(new NetUserCurrencyData() { Type = (int)currency.Key, Value = currency.Value }); + } WriteData(response); } diff --git a/nksrv/Program.cs b/nksrv/Program.cs index dfeaa84..bda504b 100644 --- a/nksrv/Program.cs +++ b/nksrv/Program.cs @@ -33,18 +33,17 @@ namespace nksrv Logger.Info("Initializing database"); JsonDb.Save(); - Logger.Info("Load static data"); + Logger.Info("Loading static data"); await StaticDataParser.Load(); - Logger.Info("Parse static data"); + Logger.Info("Parsing static data"); await StaticDataParser.Instance.Parse(); Logger.Info("Initialize handlers"); LobbyHandler.Init(); - Logger.Info("Start server"); + Logger.Info("Starting server"); - // Start Webserver using var server = CreateWebServer(); await server.RunAsync(); } diff --git a/nksrv/Protos/allmsgs.proto b/nksrv/Protos/allmsgs.proto index 8cd0fd1..dfc77cc 100644 --- a/nksrv/Protos/allmsgs.proto +++ b/nksrv/Protos/allmsgs.proto @@ -1663,4 +1663,13 @@ message ResExecuteGacha { repeated NetUserCharacterDefaultData characters = 6; repeated NetUserItemData items = 5; NetRewardData reward = 9; +} + +message NetShopProductData { + +} + +message ReqShopProductList{} +message ResShopProductList { + repeated NetShopProductData shops = 2; } \ No newline at end of file diff --git a/nksrv/StaticInfo/JsonStaticData.cs b/nksrv/StaticInfo/JsonStaticData.cs index 30f6708..0ecedeb 100644 --- a/nksrv/StaticInfo/JsonStaticData.cs +++ b/nksrv/StaticInfo/JsonStaticData.cs @@ -23,4 +23,23 @@ namespace nksrv.StaticInfo public string stage_category = ""; public int reward_id = 0; } + public class RewardTableRecord + { + public int id; + public int user_exp; + public int character_exp; + public RewardEntry[]? rewards; + } + public class RewardEntry + { + /// + /// example: 1000000 + /// + public int reward_percent; + public string percent_display_type = ""; + public string reward_type = ""; + public int reward_id; + public int reward_value; + } + } diff --git a/nksrv/StaticInfo/StaticDataParser.cs b/nksrv/StaticInfo/StaticDataParser.cs index f95af48..12685de 100644 --- a/nksrv/StaticInfo/StaticDataParser.cs +++ b/nksrv/StaticInfo/StaticDataParser.cs @@ -44,7 +44,7 @@ namespace nksrv.StaticInfo private JArray questDataRecords; private JArray stageDataRecords; private JArray rewardDataRecords; - + private JArray userExpDataRecords; public StaticDataParser(string filePath) { if (!File.Exists(filePath)) throw new ArgumentException("Static data file must exist", nameof(filePath)); @@ -202,11 +202,13 @@ namespace nksrv.StaticInfo var mainQuestData = MainZip.GetEntry("MainQuestTable.json"); var campaignStageData = MainZip.GetEntry("CampaignStageTable.json"); var rewardDataEntry = MainZip.GetEntry("RewardTable.json"); - + var userExpTable = MainZip.GetEntry("UserExpTable.json"); + if (mainQuestData == null) throw new Exception("MainQuestTable.json does not exist in static data"); if (campaignStageData == null) throw new Exception("CampaignStageTable.json does not exist in static data"); if (rewardDataEntry == null) throw new Exception("RewardTable.json does not exist in static data"); + if (userExpTable == null) throw new Exception("UserExpTable.json does not exist in static data"); using StreamReader mainQuestReader = new StreamReader(MainZip.GetInputStream(mainQuestData)); var mainQuestDataString = await mainQuestReader.ReadToEndAsync(); @@ -217,16 +219,23 @@ namespace nksrv.StaticInfo using StreamReader rewardDataReader = new StreamReader(MainZip.GetInputStream(rewardDataEntry)); var rewardJsonString = await rewardDataReader.ReadToEndAsync(); + using StreamReader userExpTableReader = new StreamReader(MainZip.GetInputStream(userExpTable)); + var userExpTableString = await userExpTableReader.ReadToEndAsync(); + var questdata = JObject.Parse(mainQuestDataString); var stagedata = JObject.Parse(campaignStageDataString); var rewardData = JObject.Parse(rewardJsonString); + var userExpTableData = JObject.Parse(userExpTableString); questDataRecords = (JArray?)questdata["records"]; stageDataRecords = (JArray?)stagedata["records"]; rewardDataRecords = (JArray?)rewardData["records"]; + userExpDataRecords = (JArray?)userExpTableData["records"]; + if (questDataRecords == null) throw new Exception("MainQuestTable.json does not contain records array"); if (stageDataRecords == null) throw new Exception("CampaignStageTable.json does not contain records array"); if (rewardDataRecords == null) throw new Exception("CampaignChapterTable.json does not contain records array"); + if (userExpDataRecords == null) throw new Exception("UserExpTable.json does not contain records array"); } public MainQuestCompletionData? GetMainQuestForStageClearCondition(int stage) @@ -283,5 +292,55 @@ namespace nksrv.StaticInfo return null; } + + public RewardTableRecord? GetRewardTableEntry(int rewardId) + { + foreach (JObject item in rewardDataRecords) + { + var id = item["id"]; + if (id == null) throw new Exception("expected id field in reward data"); + + int value = id.ToObject(); + if (value == rewardId) + { + RewardTableRecord? data = JsonConvert.DeserializeObject(item.ToString()); + if (data == null) throw new Exception("failed to deserialize reward data"); + return data; + } + } + + return null; + } + + public int GetUserLevelFromUserExp(int targetExp) + { + int prevLevel = 0; + int prevValue = 0; + for (int i = 0; i < userExpDataRecords.Count; i++) + { + var item = userExpDataRecords[i]; + + var level = item["level"]; + if (level == null) throw new Exception("expected level field in user exp table data"); + + int levelValue = level.ToObject(); + + var exp = item["exp"]; + if (exp == null) throw new Exception("expected exp field in user exp table data"); + + int expValue = exp.ToObject(); + + if (prevValue < targetExp) + { + prevLevel = levelValue; + prevValue = expValue; + } + else + { + return prevLevel; + } + } + return -1; + } } } diff --git a/nksrv/Utils/JsonDb.cs b/nksrv/Utils/JsonDb.cs index 16f6ae8..347520e 100644 --- a/nksrv/Utils/JsonDb.cs +++ b/nksrv/Utils/JsonDb.cs @@ -41,6 +41,12 @@ namespace nksrv.Utils public bool IsReceieved = false; } + public class UserPointData + { + public int UserLevel = 1; + public int ExperiencePoint = 0; + } + public class User { @@ -50,29 +56,33 @@ namespace nksrv.Utils public string PlayerName = ""; public ulong ID; public long RegisterTime; - public int LastStageCleared; - public string Nickname = "SomePLayer"; + public int LastNormalStageCleared; + public int LastHardStageCleared; + public string Nickname = "SomePlayer"; public int ProfileIconId = 39900; public bool ProfileIconIsPrism = false; - // Game data public List CompletedScenarios = []; public Dictionary FieldInfo = []; public Dictionary MapJson = []; public Dictionary Currency = new() { { CurrencyType.ContentStamina, 2 }, - { CurrencyType.CharPremiumTicket, 23422 } + { CurrencyType.CharPremiumTicket, 999999 } }; public List Characters = []; - public NetWholeUserTeamData TeamData = new(); + public NetWholeUserTeamData RepresentationTeamData = new(); public List ClearedTutorials = []; public NetWallpaperData[] WallpaperList = []; + public Dictionary UserTeams = new Dictionary(); public Dictionary MainQuestData = new() { {1, false } }; + public int InfraCoreExp = 0; + public int InfraCoreLvl = 1; + public UserPointData userPointData = new(); public void SetQuest(int tid, bool recieved) { @@ -86,11 +96,6 @@ namespace nksrv.Utils MainQuestData.Add(tid, recieved); } } - - public void RmQuest(int tid) - { - MainQuestData.Remove(tid); - } } public class CoreInfo { diff --git a/nksrv/Utils/PacketDecryption.cs b/nksrv/Utils/PacketDecryption.cs index d710b5c..ca09650 100644 --- a/nksrv/Utils/PacketDecryption.cs +++ b/nksrv/Utils/PacketDecryption.cs @@ -57,7 +57,6 @@ namespace nksrv.Utils var x = SecretAeadXChaCha20Poly1305.Decrypt(bytes, nonce, key.Keys.ReadSharedSecret, [.. additionalData]); var ms = new MemoryStream(x); - // File.WriteAllBytes("fullPkt-decr", ms.ToArray()); var unkVal1 = ms.ReadByte(); var unkVal2 = ms.ReadByte(); @@ -65,7 +64,6 @@ namespace nksrv.Utils var startPos = (int)ms.Position; - //Console.WriteLine("seg #: " + seqNum + ",actual:" + bytes.Length + "cntlen:" + ctx.Request.ContentLength64); var contents = x.Skip(startPos).ToArray(); if (contents.Length != 0 && contents[0] == 31)