diff --git a/Common/Common.csproj b/Common/Common.csproj index c0a66cbb..04252ba2 100644 --- a/Common/Common.csproj +++ b/Common/Common.csproj @@ -18,6 +18,7 @@ + diff --git a/Common/Data/Config/Scene/FloorInfo.cs b/Common/Data/Config/Scene/FloorInfo.cs index 09c30324..c2165291 100644 --- a/Common/Data/Config/Scene/FloorInfo.cs +++ b/Common/Data/Config/Scene/FloorInfo.cs @@ -1,17 +1,18 @@ -using EggLink.DanhengServer.Enums.Scene; +using System.Collections.Concurrent; +using EggLink.DanhengServer.Enums.Scene; using Newtonsoft.Json; namespace EggLink.DanhengServer.Data.Config.Scene; public class FloorInfo { - [JsonIgnore] public Dictionary CachedTeleports = []; + [JsonIgnore] public ConcurrentDictionary CachedTeleports = []; - [JsonIgnore] public Dictionary Groups = []; + [JsonIgnore] public ConcurrentDictionary Groups = []; [JsonIgnore] public bool Loaded; - [JsonIgnore] public List UnlockedCheckpoints = []; + [JsonIgnore] public ConcurrentBag UnlockedCheckpoints = []; public int FloorID { get; set; } public int StartGroupIndex { get; set; } diff --git a/Common/Data/Config/SummonUnit/UnitCustomTriggerConfigInfo.cs b/Common/Data/Config/SummonUnit/UnitCustomTriggerConfigInfo.cs index f0367a21..e0778494 100644 --- a/Common/Data/Config/SummonUnit/UnitCustomTriggerConfigInfo.cs +++ b/Common/Data/Config/SummonUnit/UnitCustomTriggerConfigInfo.cs @@ -17,8 +17,9 @@ public class UnitCustomTriggerConfigInfo public bool DependOnServerTarget { get; set; } public bool IsSingle { get; set; } // EntityType TargetEntityType { get; set; } - public DynamicFloat TargetGroupID { get; set; } - public DynamicFloat TargetID { get; set; } + public DynamicFloat TargetGroupID { get; set; } = new(); + + public DynamicFloat TargetID { get; set; } = new(); // EntityType[] TargetTypes { get; set; } // PredicateConfigInfo TargetFilter { get; set; } public string ColliderRelativePath { get; set; } = ""; diff --git a/Common/Data/Excel/RogueBuffGroupExcel.cs b/Common/Data/Excel/RogueBuffGroupExcel.cs index 92e66afc..32d114c6 100644 --- a/Common/Data/Excel/RogueBuffGroupExcel.cs +++ b/Common/Data/Excel/RogueBuffGroupExcel.cs @@ -35,7 +35,9 @@ public class RogueBuffGroupExcel : ExcelResource if (IsLoaded) return; var count = 0; foreach (var buffId in BuffTagList) - if (GameData.RogueBuffData.FirstOrDefault(x => x.Value.RogueBuffTag == buffId).Value is RogueBuffExcel buff) + { + List buffs = [.. GameData.RogueBuffData.Values]; + if (buffs.FirstOrDefault(x => x.RogueBuffTag == buffId) is { } buff) { BuffList.SafeAdd(buff); count++; @@ -48,6 +50,7 @@ public class RogueBuffGroupExcel : ExcelResource BuffList.SafeAddRange(group.BuffList); count++; } + } if (count == BuffTagList.Count) IsLoaded = true; } diff --git a/Common/Data/Excel/RogueTournBuffGroupExcel.cs b/Common/Data/Excel/RogueTournBuffGroupExcel.cs index df015ce1..312f6f14 100644 --- a/Common/Data/Excel/RogueTournBuffGroupExcel.cs +++ b/Common/Data/Excel/RogueTournBuffGroupExcel.cs @@ -34,7 +34,9 @@ public class RogueTournBuffGroupExcel : ExcelResource if (IsLoaded) return; var count = 0; foreach (var buffId in RogueBuffDrop) - if (GameData.RogueTournBuffData.FirstOrDefault(x => x.Value.RogueBuffTag == buffId).Value is { } buff) + { + List buffs = [.. GameData.RogueTournBuffData.Values]; + if (buffs.FirstOrDefault(x => x.RogueBuffTag == buffId) is { } buff) { BuffList.SafeAdd(buff); count++; @@ -47,6 +49,7 @@ public class RogueTournBuffGroupExcel : ExcelResource BuffList.SafeAddRange(group.BuffList); count++; } + } if (count == RogueBuffDrop.Count) IsLoaded = true; } diff --git a/Common/Data/GameData.cs b/Common/Data/GameData.cs index 5606d1d7..2f046121 100644 --- a/Common/Data/GameData.cs +++ b/Common/Data/GameData.cs @@ -2,6 +2,7 @@ using EggLink.DanhengServer.Data.Custom; using EggLink.DanhengServer.Data.Excel; using EggLink.DanhengServer.Enums.Rogue; +using System.Collections.Concurrent; namespace EggLink.DanhengServer.Data; @@ -98,7 +99,7 @@ public static class GameData #region Maze public static Dictionary NpcDataData { get; private set; } = []; - public static Dictionary FloorInfoData { get; } = []; + public static ConcurrentDictionary FloorInfoData { get; } = []; public static Dictionary MapEntranceData { get; private set; } = []; public static Dictionary MazePlaneData { get; private set; } = []; public static Dictionary MazePropData { get; private set; } = []; diff --git a/Common/Data/ResourceManager.cs b/Common/Data/ResourceManager.cs index be53a787..78f10e24 100644 --- a/Common/Data/ResourceManager.cs +++ b/Common/Data/ResourceManager.cs @@ -21,14 +21,18 @@ public class ResourceManager public static void LoadGameData() { LoadExcel(); - LoadFloorInfo(); - LoadMissionInfo(); - LoadMazeSkill(); - LoadSummonUnit(); - LoadDialogueInfo(); - LoadPerformanceInfo(); - LoadSubMissionInfo(); - LoadRogueChestMapInfo(); + + var t1 = Task.Run(LoadFloorInfo); + var t2 = Task.Run(LoadMazeSkill); + var t3 = Task.Run(LoadSummonUnit); + var t4 = Task.Run(() => + { + LoadMissionInfo(); + LoadSubMissionInfo(); + }); + var t5 = Task.Run(LoadPerformanceInfo); + var t6 = Task.Run(LoadDialogueInfo); + var t7 = Task.Run(LoadRogueChestMapInfo); GameData.ActivityConfig = LoadCustomFile("Activity", "ActivityConfig") ?? new ActivityConfig(); GameData.BannersConfig = LoadCustomFile("Banner", "Banners") ?? new BannersConfig(); GameData.RogueMapGenData = LoadCustomFile>>("Rogue Map", "RogueMapGen") ?? []; @@ -38,6 +42,8 @@ public class ResourceManager LoadCustomFile("Rogue Miracle Effect", "RogueMiracleEffectGen") ?? new RogueMiracleEffectConfig(); LoadChessRogueRoomData(); + + Task.WaitAll(t1, t2, t3, t4, t5, t6, t7); } public static void LoadExcel() @@ -161,8 +167,11 @@ public class ResourceManager return; } - // Load floor infos - foreach (var file in directory.GetFiles()) + var files = directory.GetFiles(); + + // Load floor infos in parallel + var res = Parallel.ForEach(files, file => + { try { using var reader = file.OpenRead(); @@ -170,7 +179,54 @@ public class ResourceManager var text = reader2.ReadToEnd(); var info = JsonConvert.DeserializeObject(text); var name = file.Name[..file.Name.IndexOf('.')]; - GameData.FloorInfoData.Add(name, info!); + if (info == null) return; + GameData.FloorInfoData[name] = info; + + // Load group infos sequentially to maintain order + foreach (var groupInfo in info.GroupInstanceList) + { + if (groupInfo.IsDelete) continue; + FileInfo groupFile = new(ConfigManager.Config.Path.ResourcePath + "/" + groupInfo.GroupPath); + if (!groupFile.Exists) continue; + + try + { + using var groupReader = groupFile.OpenRead(); + using StreamReader groupReader2 = new(groupReader); + var groupText = groupReader2.ReadToEnd(); + var group = JsonConvert.DeserializeObject(groupText); + if (group != null) + { + group.Id = groupInfo.ID; + // Use a sorted collection or maintain order manually + info.Groups[groupInfo.ID] = group; + group.Load(); + + // Load graph + var graphPath = ConfigManager.Config.Path.ResourcePath + "/" + group.LevelGraph; + var graphFile = new FileInfo(graphPath); + if (graphFile.Exists) + { + using var graphReader = graphFile.OpenRead(); + using StreamReader graphReader2 = new(graphReader); + var graphText = graphReader2.ReadToEnd().Replace("$type", "Type"); + var graphObj = JObject.Parse(graphText); + var graphInfo = LevelGraphConfigInfo.LoadFromJsonObject(graphObj); + group.LevelGraphConfig = graphInfo; + } + } + } + catch (Exception ex) + { + Logger.Error( + I18NManager.Translate("Server.ServerInfo.FailedToReadItem", groupFile.Name, + I18NManager.Translate("Word.Error")), ex); + } + } + + if (info.Groups.Count == 0) missingGroupInfos = true; + + info.OnLoad(); } catch (Exception ex) { @@ -178,63 +234,27 @@ public class ResourceManager I18NManager.Translate("Server.ServerInfo.FailedToReadItem", file.Name, I18NManager.Translate("Word.Error")), ex); } + }); - foreach (var info in GameData.FloorInfoData.Values) + // wait it done + while (!res.IsCompleted) { - foreach (var groupInfo in info.GroupInstanceList) - { - if (groupInfo.IsDelete) continue; - FileInfo file = new(ConfigManager.Config.Path.ResourcePath + "/" + groupInfo.GroupPath); - if (!file.Exists) continue; - try - { - using var reader = file.OpenRead(); - using StreamReader reader2 = new(reader); - var text = reader2.ReadToEnd(); - var group = JsonConvert.DeserializeObject(text); - if (group != null) - { - group.Id = groupInfo.ID; - info.Groups.TryAdd(groupInfo.ID, group); - group.Load(); - - // load graph - var graphPath = ConfigManager.Config.Path.ResourcePath + "/" + group.LevelGraph; - var graphFile = new FileInfo(graphPath); - if (graphFile.Exists) - { - using var graphReader = graphFile.OpenRead(); - using StreamReader graphReader2 = new(graphReader); - var graphText = graphReader2.ReadToEnd().Replace("$type", "Type"); - var graphObj = JObject.Parse(graphText); - var graphInfo = LevelGraphConfigInfo.LoadFromJsonObject(graphObj); - group.LevelGraphConfig = graphInfo; - } - } - } - catch (Exception ex) - { - Logger.Error( - I18NManager.Translate("Server.ServerInfo.FailedToReadItem", file.Name, - I18NManager.Translate("Word.Error")), ex); - } - - if (info.Groups.Count == 0) missingGroupInfos = true; - } - - info.OnLoad(); + Thread.Sleep(10); } if (missingGroupInfos) + { Logger.Warn(I18NManager.Translate("Server.ServerInfo.ConfigMissing", I18NManager.Translate("Word.FloorGroupInfo"), $"{ConfigManager.Config.Path.ResourcePath}/Config/LevelOutput/SharedRuntimeGroup", I18NManager.Translate("Word.FloorGroupMissingResult"))); + } Logger.Info(I18NManager.Translate("Server.ServerInfo.LoadedItems", GameData.FloorInfoData.Count.ToString(), I18NManager.Translate("Word.FloorInfo"))); } + public static void LoadMissionInfo() { Logger.Info(I18NManager.Translate("Server.ServerInfo.LoadingItem", I18NManager.Translate("Word.MissionInfo"))); @@ -250,14 +270,14 @@ public class ResourceManager var missingMissionInfos = false; var count = 0; - foreach (var missionExcel in GameData.MainMissionData) + var res = Parallel.ForEach(GameData.MainMissionData, missionExcel => { var path = $"{ConfigManager.Config.Path.ResourcePath}/Config/Level/Mission/{missionExcel.Key}/MissionInfo_{missionExcel.Key}.json"; if (!File.Exists(path)) { missingMissionInfos = true; - continue; + return; } var json = File.ReadAllText(path); @@ -271,6 +291,12 @@ public class ResourceManager { missingMissionInfos = true; } + }); + + // wait it done + while (!res.IsCompleted) + { + Thread.Sleep(10); } if (missingMissionInfos) @@ -340,14 +366,14 @@ public class ResourceManager Logger.Info(I18NManager.Translate("Server.ServerInfo.LoadingItem", I18NManager.Translate("Word.MazeSkillInfo"))); var count = 0; - foreach (var adventure in GameData.AdventurePlayerData.Values) + var res = Parallel.ForEach(GameData.AdventurePlayerData.Values, adventure => { var avatar = GameData.AvatarConfigData[adventure.AvatarID]; var adventurePath = adventure.PlayerJsonPath.Replace("_Config.json", "_Ability.json") .Replace("ConfigCharacter", "ConfigAdventureAbility"); var path = ConfigManager.Config.Path.ResourcePath + "/" + adventurePath; var file = new FileInfo(path); - if (!file.Exists) continue; + if (!file.Exists) return; try { using var reader = file.OpenRead(); @@ -363,6 +389,12 @@ public class ResourceManager I18NManager.Translate("Server.ServerInfo.FailedToReadItem", adventurePath, I18NManager.Translate("Word.Error")), ex); } + }); + + // wait it done + while (!res.IsCompleted) + { + Thread.Sleep(10); } if (count < GameData.AdventurePlayerData.Count) @@ -380,11 +412,11 @@ public class ResourceManager Logger.Info(I18NManager.Translate("Server.ServerInfo.LoadingItem", I18NManager.Translate("Word.SummonUnitInfo"))); var count = 0; - foreach (var summonUnit in GameData.SummonUnitDataData.Values) + var res = Parallel.ForEach(GameData.SummonUnitDataData.Values, summonUnit => { var path = ConfigManager.Config.Path.ResourcePath + "/" + summonUnit.JsonPath; var file = new FileInfo(path); - if (!file.Exists) continue; + if (!file.Exists) return; try { using var reader = file.OpenRead(); @@ -403,6 +435,12 @@ public class ResourceManager I18NManager.Translate("Server.ServerInfo.FailedToReadItem", summonUnit.JsonPath, I18NManager.Translate("Word.Error")), ex); } + }); + + // wait it done + while (!res.IsCompleted) + { + Thread.Sleep(10); } if (count < GameData.SummonUnitDataData.Count) @@ -419,23 +457,21 @@ public class ResourceManager { Logger.Info(I18NManager.Translate("Server.ServerInfo.LoadingItem", I18NManager.Translate("Word.DialogueInfo"))); var count = 0; - foreach (var dialogue in GameData.RogueNPCData) + var res = Parallel.ForEach(GameData.RogueNPCData.Values, dialogue => { - var path = ConfigManager.Config.Path.ResourcePath + "/" + dialogue.Value.NPCJsonPath; + var path = ConfigManager.Config.Path.ResourcePath + "/" + dialogue.NPCJsonPath; var file = new FileInfo(path); - if (!file.Exists) continue; + if (!file.Exists) return; try { using var reader = file.OpenRead(); using StreamReader reader2 = new(reader); var text = reader2.ReadToEnd().Replace("$type", "Type"); var dialogueInfo = JsonConvert.DeserializeObject(text); - if (dialogueInfo != null) - { - dialogue.Value.RogueNpcConfig = dialogueInfo; - dialogueInfo.Loaded(); - count++; - } + if (dialogueInfo == null) return; + dialogue.RogueNpcConfig = dialogueInfo; + count++; + dialogueInfo.Loaded(); } catch (Exception ex) { @@ -443,6 +479,12 @@ public class ResourceManager I18NManager.Translate("Server.ServerInfo.FailedToReadItem", file.Name, I18NManager.Translate("Word.Error")), ex); } + }); + + // wait it done + while (!res.IsCompleted) + { + Thread.Sleep(10); } if (count < GameData.RogueNPCData.Count) @@ -460,17 +502,18 @@ public class ResourceManager Logger.Info(I18NManager.Translate("Server.ServerInfo.LoadingItem", I18NManager.Translate("Word.PerformanceInfo"))); var count = 0; - foreach (var performance in GameData.PerformanceEData.Values) + + var res = Parallel.ForEach(GameData.PerformanceEData.Values, performance => { if (performance.PerformancePath == "") { count++; - continue; + return; } var path = ConfigManager.Config.Path.ResourcePath + "/" + performance.PerformancePath; var file = new FileInfo(path); - if (!file.Exists) continue; + if (!file.Exists) return; try { using var reader = file.OpenRead(); @@ -487,19 +530,19 @@ public class ResourceManager I18NManager.Translate("Server.ServerInfo.FailedToReadItem", file.Name, I18NManager.Translate("Word.Error")), ex); } - } + }); - foreach (var performance in GameData.PerformanceDData.Values) + var res2 = Parallel.ForEach(GameData.PerformanceDData.Values, performance => { if (performance.PerformancePath == "") { count++; - continue; + return; } var path = ConfigManager.Config.Path.ResourcePath + "/" + performance.PerformancePath; var file = new FileInfo(path); - if (!file.Exists) continue; + if (!file.Exists) return; try { using var reader = file.OpenRead(); @@ -516,6 +559,12 @@ public class ResourceManager I18NManager.Translate("Server.ServerInfo.FailedToReadItem", file.Name, I18NManager.Translate("Word.Error")), ex); } + }); + + // wait it done + while (!(res.IsCompleted && res2.IsCompleted)) + { + Thread.Sleep(10); } if (count < GameData.PerformanceEData.Count + GameData.PerformanceDData.Count) @@ -533,13 +582,13 @@ public class ResourceManager Logger.Info( I18NManager.Translate("Server.ServerInfo.LoadingItem", I18NManager.Translate("Word.SubMissionInfo"))); var count = 0; - foreach (var subMission in GameData.SubMissionData.Values) + var res = Parallel.ForEach(GameData.SubMissionData.Values, subMission => { - if (subMission.SubMissionInfo == null || subMission.SubMissionInfo.MissionJsonPath == "") continue; + if (subMission.SubMissionInfo == null || subMission.SubMissionInfo.MissionJsonPath == "") return; var path = ConfigManager.Config.Path.ResourcePath + "/" + subMission.SubMissionInfo.MissionJsonPath; var file = new FileInfo(path); - if (!file.Exists) continue; + if (!file.Exists) return; try { using var reader = file.OpenRead(); @@ -556,6 +605,12 @@ public class ResourceManager I18NManager.Translate("Server.ServerInfo.FailedToReadItem", file.Name, I18NManager.Translate("Word.Error")), ex); } + }); + + // wait it done + while (!res.IsCompleted) + { + Thread.Sleep(10); } if (count < GameData.SubMissionData.Count) diff --git a/Common/Database/DatabaseHelper.cs b/Common/Database/DatabaseHelper.cs index 37c4a5c7..cd2645af 100644 --- a/Common/Database/DatabaseHelper.cs +++ b/Common/Database/DatabaseHelper.cs @@ -1,4 +1,7 @@ -using System.Globalization; +using System.Collections.Concurrent; +using System.Globalization; +using EggLink.DanhengServer.Data.Excel; +using EggLink.DanhengServer.Database.Account; using EggLink.DanhengServer.Database.Inventory; using EggLink.DanhengServer.Database.Quests; using EggLink.DanhengServer.Internationalization; @@ -12,10 +15,12 @@ public class DatabaseHelper public static Logger logger = new("Database"); public static SqlSugarScope? sqlSugarScope; public static DatabaseHelper? Instance; - public static readonly Dictionary> UidInstanceMap = []; + public static readonly ConcurrentDictionary> UidInstanceMap = []; public static readonly List ToSaveUidList = []; public static long LastSaveTick = DateTime.UtcNow.Ticks; public static Thread? SaveThread; + public static bool LoadAccount = false; + public static bool LoadAllData = false; public DatabaseHelper() { @@ -71,10 +76,42 @@ public class DatabaseHelper var baseType = typeof(BaseDatabaseDataHelper); var assembly = typeof(BaseDatabaseDataHelper).Assembly; + var types = assembly.GetTypes().Where(t => t.IsSubclassOf(baseType)); - foreach (var t in types) - typeof(DatabaseHelper).GetMethod("InitializeTable")?.MakeGenericMethod(t) - .Invoke(null, null); // cache the data + + var list = sqlSugarScope.Queryable() + .Select(x => x) + .ToList(); + + foreach (var inst in list!.Select(instance => (instance as BaseDatabaseDataHelper)!)) + { + if (!UidInstanceMap.TryGetValue(inst.Uid, out var value)) + { + value = []; + UidInstanceMap[inst.Uid] = value; + } + + value.Add(inst); // add to the map + } + + // start dispatch server + LoadAccount = true; + + var res = Parallel.ForEach(list, account => + { + Parallel.ForEach(types, t => + { + if (t == typeof(AccountData)) return; // skip the account data + + typeof(DatabaseHelper).GetMethod(nameof(InitializeTable))?.MakeGenericMethod(t) + .Invoke(null, [account.Uid]); + }); // cache the data + }); + + while (!res.IsCompleted) + { + + } LastSaveTick = DateTime.UtcNow.Ticks; @@ -83,12 +120,16 @@ public class DatabaseHelper while (true) CalcSaveDatabase(); }); SaveThread.Start(); + + LoadAllData = true; } - public static void InitializeTable() where T : class, new() + public static void InitializeTable(int uid) where T : BaseDatabaseDataHelper, new() { var list = sqlSugarScope?.Queryable() .Select(x => x) + .Select() + .Where(x => x.Uid == uid) .ToList(); foreach (var inst in list!.Select(instance => (instance as BaseDatabaseDataHelper)!)) diff --git a/Common/Internationalization/Message/LanguageCHS.cs b/Common/Internationalization/Message/LanguageCHS.cs index dc75c665..460df56b 100644 --- a/Common/Internationalization/Message/LanguageCHS.cs +++ b/Common/Internationalization/Message/LanguageCHS.cs @@ -80,6 +80,8 @@ public class WordTextCHS public string RogueChestMapInfo => "模拟宇宙地图文件"; public string ChessRogueRoom => "模拟宇宙DLC"; public string ChessRogueRoomInfo => "模拟宇宙DLC文件"; + + public string DatabaseAccount => "数据库账号"; } #endregion @@ -150,6 +152,7 @@ public class ServerInfoTextCHS public string ConfigMissing => "{0} 缺失,请检查你的资源文件夹:{1},{2} 可能不能使用。"; public string UnloadedItems => "卸载了所有 {0}。"; public string SaveDatabase => "已保存数据库,用时 {0}s"; + public string WaitForAllDone => "现在还不可以进入游戏,请等待所有项目加载完成后再试"; } #endregion diff --git a/Common/Internationalization/Message/LanguageCHT.cs b/Common/Internationalization/Message/LanguageCHT.cs index 41a973a4..92e9be51 100644 --- a/Common/Internationalization/Message/LanguageCHT.cs +++ b/Common/Internationalization/Message/LanguageCHT.cs @@ -80,6 +80,8 @@ public class WordTextCHT public string RogueChestMapInfo => "模擬宇宙地圖文件"; public string ChessRogueRoom => "模擬宇宙DLC"; public string ChessRogueRoomInfo => "模擬宇宙DLC文件"; + + public string DatabaseAccount => "數據庫賬號"; } #endregion @@ -150,6 +152,7 @@ public class ServerInfoTextCHT public string ConfigMissing => "{0} 缺失,請檢查你的資源文件夾:{1},{2} 可能不能使用。"; public string UnloadedItems => "卸載了所有 {0}。"; public string SaveDatabase => "已保存數據庫,用時 {0}s"; + public string WaitForAllDone => "現在還不可以進入遊戲,請等待所有項目加載完成後再試"; } #endregion diff --git a/Common/Internationalization/Message/LanguageEN.cs b/Common/Internationalization/Message/LanguageEN.cs index feaf09cb..eb87f74f 100644 --- a/Common/Internationalization/Message/LanguageEN.cs +++ b/Common/Internationalization/Message/LanguageEN.cs @@ -80,6 +80,8 @@ public class WordTextEN public string RogueChestMapInfo => "Simulated Universe Map Info"; public string ChessRogueRoom => "Simulated Universe DLC"; public string ChessRogueRoomInfo => "Simulated Universe DLC Info"; + + public string DatabaseAccount => "Database Account"; } #endregion @@ -154,6 +156,8 @@ public class ServerInfoTextEN public string ConfigMissing => "{0} is missing. Please check your resource folder: {1}, {2} may not be available."; public string UnloadedItems => "Unloaded all {0}."; public string SaveDatabase => "Database saved in {0}s"; + + public string WaitForAllDone => "You cannot enter the game yet. Please wait for all items to load before trying again"; } #endregion diff --git a/DanhengKcpSharp/DanhengConnection.cs b/DanhengKcpSharp/DanhengConnection.cs index 3e44ebe0..ec31cc75 100644 --- a/DanhengKcpSharp/DanhengConnection.cs +++ b/DanhengKcpSharp/DanhengConnection.cs @@ -1,4 +1,6 @@ -using System.Net; +using System.Collections.Concurrent; +using System.IO.Pipelines; +using System.Net; using System.Reflection; using EggLink.DanhengServer.Kcp.KcpSharp; using EggLink.DanhengServer.Util; @@ -11,11 +13,11 @@ public class DanhengConnection { public const int MAX_MSG_SIZE = 16384; public const int HANDSHAKE_SIZE = 20; - public static readonly List BannedPackets = []; + public static readonly ConcurrentBag BannedPackets = []; private static readonly Logger Logger = new("GameServer"); - public static readonly Dictionary LogMap = []; + public static readonly ConcurrentDictionary LogMap = []; - public static readonly List IgnoreLog = + public static readonly ConcurrentBag IgnoreLog = [ CmdIds.PlayerHeartBeatCsReq, CmdIds.PlayerHeartBeatScRsp, CmdIds.SceneEntityMoveCsReq, CmdIds.SceneEntityMoveScRsp, CmdIds.GetShopListCsReq, CmdIds.GetShopListScRsp diff --git a/DanhengKcpSharp/DanhengKcpSharp.csproj b/DanhengKcpSharp/DanhengKcpSharp.csproj index 367c1764..0bc5bbe5 100644 --- a/DanhengKcpSharp/DanhengKcpSharp.csproj +++ b/DanhengKcpSharp/DanhengKcpSharp.csproj @@ -10,6 +10,7 @@ + diff --git a/GameServer/GameServer.csproj b/GameServer/GameServer.csproj index 9a712eb0..94b8148b 100644 --- a/GameServer/GameServer.csproj +++ b/GameServer/GameServer.csproj @@ -22,6 +22,7 @@ + diff --git a/Program/Program/EntryPoint.cs b/Program/Program/EntryPoint.cs index 41623a25..67249c91 100644 --- a/Program/Program/EntryPoint.cs +++ b/Program/Program/EntryPoint.cs @@ -25,7 +25,7 @@ public class EntryPoint public static readonly Listener Listener = new(); public static readonly CommandManager CommandManager = new(); - public static void Main(string[] args) + public static async Task Main(string[] args) { AppDomain.CurrentDomain.ProcessExit += (_, _) => { @@ -85,11 +85,15 @@ public class EntryPoint // Initialize the database try { - DatabaseHelper.Initialize(); + _ = Task.Run(DatabaseHelper.Initialize); // do not wait - if (args.Contains("--upgrade-database")) DatabaseHelper.UpgradeDatabase(); + while (!DatabaseHelper.LoadAccount) + { + Thread.Sleep(100); + } - if (args.Contains("--move")) DatabaseHelper.MoveFromSqlite(); + Logger.Info(I18NManager.Translate("Server.ServerInfo.LoadedItem", I18NManager.Translate("Word.DatabaseAccount"))); + Logger.Warn(I18NManager.Translate("Server.ServerInfo.WaitForAllDone")); } catch (Exception e) { @@ -211,6 +215,26 @@ public class EntryPoint // generate the handbook HandbookGenerator.Generate(); + if (!DatabaseHelper.LoadAllData) + { + Logger.Warn(I18NManager.Translate("Server.ServerInfo.WaitForAllDone")); + var t = Task.Run(() => + { + while (!DatabaseHelper.LoadAllData) // wait for all data to be loaded + { + Thread.Sleep(100); + } + }); + + await t.WaitAsync(new CancellationToken()); + + Logger.Info(I18NManager.Translate("Server.ServerInfo.LoadedItem", I18NManager.Translate("Word.Database"))); + } + + if (args.Contains("--upgrade-database")) DatabaseHelper.UpgradeDatabase(); + + if (args.Contains("--move")) DatabaseHelper.MoveFromSqlite(); + var elapsed = DateTime.Now - time; Logger.Info(I18NManager.Translate("Server.ServerInfo.ServerStarted", Math.Round(elapsed.TotalSeconds, 2).ToString(CultureInfo.InvariantCulture))); @@ -245,7 +269,7 @@ public class EntryPoint { var name = opcode.Name; var value = (int)opcode.GetValue(null)!; - DanhengConnection.LogMap.Add(value, name); + DanhengConnection.LogMap.TryAdd(value, name); } } } \ No newline at end of file diff --git a/WebServer/Controllers/GateServerRoutes.cs b/WebServer/Controllers/GateServerRoutes.cs index 60713ae8..a00b3129 100644 --- a/WebServer/Controllers/GateServerRoutes.cs +++ b/WebServer/Controllers/GateServerRoutes.cs @@ -8,8 +8,9 @@ namespace EggLink.DanhengServer.WebServer.Controllers; public class GateServerRoutes { [HttpGet("/query_gateway")] - public string QueryGateway() + public async ValueTask QueryGateway() { + await ValueTask.CompletedTask; return new QueryGatewayHandler().Data; } } \ No newline at end of file