From cce8179e8d450cf9d0a0ec10325ec904bca65c9e Mon Sep 17 00:00:00 2001 From: Mikhail Date: Fri, 26 Jul 2024 12:49:11 -0400 Subject: [PATCH] implement ban, add static data progress bar, allow changing server name --- nksrv/Database/JsonDb.cs | 6 ++ nksrv/LobbyServer/Msgs/Auth/DoIntlAuth.cs | 43 ++++++++- nksrv/Program.cs | 6 +- nksrv/StaticInfo/StaticDataParser.cs | 39 ++++---- nksrv/Utils/ProgressBar.cs | 105 ++++++++++++++++++++++ 5 files changed, 178 insertions(+), 21 deletions(-) create mode 100644 nksrv/Utils/ProgressBar.cs diff --git a/nksrv/Database/JsonDb.cs b/nksrv/Database/JsonDb.cs index 528b391..eea4149 100644 --- a/nksrv/Database/JsonDb.cs +++ b/nksrv/Database/JsonDb.cs @@ -79,6 +79,11 @@ namespace nksrv.Database public bool ProfileIconIsPrism = false; public bool IsAdmin = false; + public bool IsBanned = false; + public DateTime BanStart; + public DateTime BanEnd; + public int BanId = 0; + // Game data public List CompletedScenarios = []; public Dictionary FieldInfo = []; // here for backwards compatibility @@ -202,6 +207,7 @@ namespace nksrv.Database public List LauncherAccessTokens = []; public Dictionary GameClientTokens = []; + public string ServerName = "Private Server"; } internal class JsonDb { diff --git a/nksrv/LobbyServer/Msgs/Auth/DoIntlAuth.cs b/nksrv/LobbyServer/Msgs/Auth/DoIntlAuth.cs index 9346c1b..17e5910 100644 --- a/nksrv/LobbyServer/Msgs/Auth/DoIntlAuth.cs +++ b/nksrv/LobbyServer/Msgs/Auth/DoIntlAuth.cs @@ -1,4 +1,7 @@ -using nksrv.Utils; +using EmbedIO; +using Google.Protobuf.WellKnownTypes; +using nksrv.Database; +using nksrv.Utils; namespace nksrv.LobbyServer.Msgs.Auth { @@ -8,10 +11,42 @@ namespace nksrv.LobbyServer.Msgs.Auth protected override async Task HandleAsync() { var req = await ReadData(); - var response = new AuthIntlResponse(); - //response.BanInfo = new NetBanInfo() { BanId = 123, Description = "The server admin is sad today because the hinge on his HP laptop broke which happened to be an HP Elitebook 8470p, and the RAM controller exploded and then fixed itself, please contact him", StartAt = Timestamp.FromDateTime(DateTime.UtcNow), EndAt = Timestamp.FromDateTime(DateTime.UtcNow.AddDays(256)) }; - response.AuthSuccess = new NetAuthSuccess() { AuthToken = req.Token, CentauriZoneId = "84", FirstAuth = "", PurchaseRestriction = new NetUserPurchaseRestriction() { PurchaseRestriction = PurchaseRestriction.Unknown2, UpdatedAt = 638546758794611090 } }; + + UsedAuthToken = req.Token; + foreach (var item in JsonDb.Instance.LauncherAccessTokens) + { + if (item.Token == UsedAuthToken) + { + UserId = item.UserID; + } + } + if (UserId == 0) + { + response.AuthError = new NetAuthError() { ErrorCode = AuthErrorCode.Error }; + } + else + { + var user = GetUser(); + + if (user.IsBanned && user.BanEnd < DateTime.UtcNow) + { + user.IsBanned = false; + user.BanId = 0; + user.BanStart = DateTime.MinValue; + user.BanEnd = DateTime.MinValue; + JsonDb.Save(); + } + + if (user.IsBanned) + { + response.BanInfo = new NetBanInfo() { BanId = user.BanId, Description = "The server admin is sad today because the hinge on his HP laptop broke which happened to be an HP Elitebook 8470p, and the RAM controller exploded and then fixed itself, please contact him", StartAt = Timestamp.FromDateTime(DateTime.SpecifyKind(user.BanStart, DateTimeKind.Utc)), EndAt = Timestamp.FromDateTime(DateTime.SpecifyKind(user.BanEnd, DateTimeKind.Utc)) }; + } + else + { + response.AuthSuccess = new NetAuthSuccess() { AuthToken = req.Token, CentauriZoneId = "84", FirstAuth = "", PurchaseRestriction = new NetUserPurchaseRestriction() { PurchaseRestriction = PurchaseRestriction.Child, UpdatedAt = 638546758794611090 } }; + } + } await WriteDataAsync(response); } diff --git a/nksrv/Program.cs b/nksrv/Program.cs index 39e0193..6ba97e1 100644 --- a/nksrv/Program.cs +++ b/nksrv/Program.cs @@ -1,6 +1,7 @@ using EmbedIO; using EmbedIO.Actions; using EmbedIO.WebApi; +using Newtonsoft.Json; using nksrv.Database; using nksrv.IntlServer; using nksrv.LobbyServer; @@ -450,7 +451,7 @@ namespace nksrv ""WorldId"": 1001, ""Name"": ""pub:priv"", ""Url"": ""https://global-lobby.nikke-kr.com/"", - ""Description"": ""Private Server"", + ""Description"": {ServerName}, ""Tags"": [] } ] @@ -466,7 +467,7 @@ namespace nksrv ""WorldId"": 1001, ""Name"": ""pub:priv"", ""Url"": ""https://global-lobby.nikke-kr.com/"", - ""Description"": ""Private Server"", + ""Description"": {ServerName}, ""Tags"": [] } ] @@ -475,6 +476,7 @@ namespace nksrv }"; response = response.Replace("{GameMinVer}", GameConfig.Root.GameMinVer); response = response.Replace("{GameMaxVer}", GameConfig.Root.GameMaxVer); + response = response.Replace("{ServerName}", JsonConvert.ToString(JsonDb.Instance.ServerName)); await ctx.SendStringAsync(response, "application/json", Encoding.Default); } else diff --git a/nksrv/StaticInfo/StaticDataParser.cs b/nksrv/StaticInfo/StaticDataParser.cs index 5838054..4c374a4 100644 --- a/nksrv/StaticInfo/StaticDataParser.cs +++ b/nksrv/StaticInfo/StaticDataParser.cs @@ -56,10 +56,10 @@ namespace nksrv.StaticInfo static async Task BuildAsync() { - Logger.Info("Loading static data"); + Logger.Info("Decrypting static data"); await Load(); - Logger.Info("Parsing static data"); + Logger.Info("Loading static data"); await Instance.Parse(); return Instance; @@ -212,7 +212,7 @@ namespace nksrv.StaticInfo } #endregion - private async Task LoadZip(string entry) + private async Task LoadZip(string entry, ProgressBar bar) { var mainQuestData = MainZip.GetEntry(entry); if (mainQuestData == null) throw new Exception(entry + " does not exist in static data"); @@ -227,20 +227,29 @@ namespace nksrv.StaticInfo var records = (JArray?)questdata["records"]; if (records == null) throw new Exception(entry + " is missing records element"); + currentFile++; + bar.Report((double)currentFile / totalFiles); + return records; } + int totalFiles = 12; + int currentFile = 0; public async Task Parse() { - questDataRecords = await LoadZip("MainQuestTable.json"); - stageDataRecords = await LoadZip("CampaignStageTable.json"); - rewardDataRecords = await LoadZip("RewardTable.json"); - userExpDataRecords = await LoadZip("UserExpTable.json"); - chapterCampaignData = await LoadZip("CampaignChapterTable.json"); - characterCostumeTable = await LoadZip("CharacterCostumeTable.json"); - characterTable = await LoadZip("CharacterTable.json"); - tutorialTable = await LoadZip("ContentsTutorialTable.json"); - itemEquipTable = await LoadZip("ItemEquipTable.json"); - var characterLevelTable = await LoadZip("CharacterLevelTable.json"); + using var progress = new ProgressBar(); + + + + questDataRecords = await LoadZip("MainQuestTable.json", progress); + stageDataRecords = await LoadZip("CampaignStageTable.json", progress); + rewardDataRecords = await LoadZip("RewardTable.json", progress); + userExpDataRecords = await LoadZip("UserExpTable.json", progress); + chapterCampaignData = await LoadZip("CampaignChapterTable.json", progress); + characterCostumeTable = await LoadZip("CharacterCostumeTable.json", progress); + characterTable = await LoadZip("CharacterTable.json", progress); + tutorialTable = await LoadZip("ContentsTutorialTable.json", progress); + itemEquipTable = await LoadZip("ItemEquipTable.json", progress); + var characterLevelTable = await LoadZip("CharacterLevelTable.json", progress); foreach (JToken item in characterLevelTable) { @@ -251,7 +260,7 @@ namespace nksrv.StaticInfo Logger.Warn("failed to read character level table entry"); } - var tacticLessonTable = await LoadZip("TacticAcademyFunctionTable.json"); + var tacticLessonTable = await LoadZip("TacticAcademyFunctionTable.json", progress); foreach (JToken item in tacticLessonTable) { @@ -274,7 +283,7 @@ namespace nksrv.StaticInfo TacticAcademyLessons.Add(id, new TacticAcademyLessonRecord() { CurrencyId = (CurrencyType)currencyId, CurrencyValue = currencyValue, GroupId = groupid, Id = id }); } - var sideStoryTable = await LoadZip("SideStoryStageTable.json"); + var sideStoryTable = await LoadZip("SideStoryStageTable.json", progress); foreach (JToken item in sideStoryTable) { diff --git a/nksrv/Utils/ProgressBar.cs b/nksrv/Utils/ProgressBar.cs new file mode 100644 index 0000000..5ce9658 --- /dev/null +++ b/nksrv/Utils/ProgressBar.cs @@ -0,0 +1,105 @@ +// Source code is from: https://gist.github.com/DanielSWolf/0ab6a96899cc5377bf54 +// Licensed under MIT License + +using System.Text; + +namespace nksrv.Utils +{ + /// + /// An ASCII progress bar + /// + public class ProgressBar : IDisposable, IProgress + { + private const int blockCount = 10; + private readonly TimeSpan animationInterval = TimeSpan.FromSeconds(1.0 / 8); + private const string animation = @"|/-\"; + + private readonly Timer timer; + + private double currentProgress = 0; + private string currentText = string.Empty; + private bool disposed = false; + private int animationIndex = 0; + + public ProgressBar() + { + timer = new Timer(TimerHandler); + + // A progress bar is only for temporary display in a console window. + // If the console output is redirected to a file, draw nothing. + // Otherwise, we'll end up with a lot of garbage in the target file. + if (!Console.IsOutputRedirected) + { + ResetTimer(); + } + } + + public void Report(double value) + { + // Make sure value is in [0..1] range + value = Math.Max(0, Math.Min(1, value)); + Interlocked.Exchange(ref currentProgress, value); + } + + private void TimerHandler(object state) + { + lock (timer) + { + if (disposed) return; + + int progressBlockCount = (int)(currentProgress * blockCount); + int percent = (int)(currentProgress * 100); + string text = string.Format("[{0}{1}] {2,3}% {3}", + new string('#', progressBlockCount), new string('-', blockCount - progressBlockCount), + percent, + animation[animationIndex++ % animation.Length]); + UpdateText(text); + + ResetTimer(); + } + } + + private void UpdateText(string text) + { + // Get length of common portion + int commonPrefixLength = 0; + int commonLength = Math.Min(currentText.Length, text.Length); + while (commonPrefixLength < commonLength && text[commonPrefixLength] == currentText[commonPrefixLength]) + { + commonPrefixLength++; + } + + // Backtrack to the first differing character + StringBuilder outputBuilder = new StringBuilder(); + outputBuilder.Append('\b', currentText.Length - commonPrefixLength); + + // Output new suffix + outputBuilder.Append(text.Substring(commonPrefixLength)); + + // If the new text is shorter than the old one: delete overlapping characters + int overlapCount = currentText.Length - text.Length; + if (overlapCount > 0) + { + outputBuilder.Append(' ', overlapCount); + outputBuilder.Append('\b', overlapCount); + } + + Console.Write(outputBuilder); + currentText = text; + } + + private void ResetTimer() + { + timer.Change(animationInterval, TimeSpan.FromMilliseconds(-1)); + } + + public void Dispose() + { + lock (timer) + { + disposed = true; + UpdateText(string.Empty); + } + } + } +}