mirror of
https://github.com/EggLinks/DanhengServer-OpenSource.git
synced 2026-01-02 20:26:03 +08:00
Better performance of loading resources
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
<PackageReference Include="SQLitePCLRaw.core" Version="2.1.8" />
|
||||
<PackageReference Include="SQLitePCLRaw.provider.e_sqlite3" Version="2.1.8" />
|
||||
<PackageReference Include="SqlSugarCore" Version="5.1.4.167" />
|
||||
<PackageReference Include="System.IO.Pipelines" Version="8.0.0" />
|
||||
<PackageReference Include="System.Management" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -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<int, PropInfo> CachedTeleports = [];
|
||||
[JsonIgnore] public ConcurrentDictionary<int, PropInfo> CachedTeleports = [];
|
||||
|
||||
[JsonIgnore] public Dictionary<int, GroupInfo> Groups = [];
|
||||
[JsonIgnore] public ConcurrentDictionary<int, GroupInfo> Groups = [];
|
||||
|
||||
[JsonIgnore] public bool Loaded;
|
||||
|
||||
[JsonIgnore] public List<PropInfo> UnlockedCheckpoints = [];
|
||||
[JsonIgnore] public ConcurrentBag<PropInfo> UnlockedCheckpoints = [];
|
||||
|
||||
public int FloorID { get; set; }
|
||||
public int StartGroupIndex { get; set; }
|
||||
|
||||
@@ -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; } = "";
|
||||
|
||||
@@ -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<RogueBuffExcel> 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;
|
||||
}
|
||||
|
||||
@@ -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<RogueTournBuffExcel> 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;
|
||||
}
|
||||
|
||||
@@ -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<int, NPCDataExcel> NpcDataData { get; private set; } = [];
|
||||
public static Dictionary<string, FloorInfo> FloorInfoData { get; } = [];
|
||||
public static ConcurrentDictionary<string, FloorInfo> FloorInfoData { get; } = [];
|
||||
public static Dictionary<int, MapEntranceExcel> MapEntranceData { get; private set; } = [];
|
||||
public static Dictionary<int, MazePlaneExcel> MazePlaneData { get; private set; } = [];
|
||||
public static Dictionary<int, MazePropExcel> MazePropData { get; private set; } = [];
|
||||
|
||||
@@ -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<ActivityConfig>("Activity", "ActivityConfig") ?? new ActivityConfig();
|
||||
GameData.BannersConfig = LoadCustomFile<BannersConfig>("Banner", "Banners") ?? new BannersConfig();
|
||||
GameData.RogueMapGenData = LoadCustomFile<Dictionary<int, List<int>>>("Rogue Map", "RogueMapGen") ?? [];
|
||||
@@ -38,6 +42,8 @@ public class ResourceManager
|
||||
LoadCustomFile<RogueMiracleEffectConfig>("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<FloorInfo>(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<GroupInfo>(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<GroupInfo>(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<RogueNPCConfigInfo>(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)
|
||||
|
||||
@@ -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<int, List<BaseDatabaseDataHelper>> UidInstanceMap = [];
|
||||
public static readonly ConcurrentDictionary<int, List<BaseDatabaseDataHelper>> UidInstanceMap = [];
|
||||
public static readonly List<int> 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<AccountData>()
|
||||
.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<T>() where T : class, new()
|
||||
public static void InitializeTable<T>(int uid) where T : BaseDatabaseDataHelper, new()
|
||||
{
|
||||
var list = sqlSugarScope?.Queryable<T>()
|
||||
.Select(x => x)
|
||||
.Select<T>()
|
||||
.Where(x => x.Uid == uid)
|
||||
.ToList();
|
||||
|
||||
foreach (var inst in list!.Select(instance => (instance as BaseDatabaseDataHelper)!))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<int> BannedPackets = [];
|
||||
public static readonly ConcurrentBag<int> BannedPackets = [];
|
||||
private static readonly Logger Logger = new("GameServer");
|
||||
public static readonly Dictionary<int, string> LogMap = [];
|
||||
public static readonly ConcurrentDictionary<int, string> LogMap = [];
|
||||
|
||||
public static readonly List<int> IgnoreLog =
|
||||
public static readonly ConcurrentBag<int> IgnoreLog =
|
||||
[
|
||||
CmdIds.PlayerHeartBeatCsReq, CmdIds.PlayerHeartBeatScRsp, CmdIds.SceneEntityMoveCsReq,
|
||||
CmdIds.SceneEntityMoveScRsp, CmdIds.GetShopListCsReq, CmdIds.GetShopListScRsp
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.27.3" />
|
||||
<PackageReference Include="System.IO.Pipelines" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<ProjectReference Include="..\Proto\Proto.csproj" />
|
||||
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
|
||||
<PackageReference Include="McMaster.NETCore.Plugins.Mvc" Version="1.4.0" />
|
||||
<PackageReference Include="System.IO.Pipelines" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,9 @@ namespace EggLink.DanhengServer.WebServer.Controllers;
|
||||
public class GateServerRoutes
|
||||
{
|
||||
[HttpGet("/query_gateway")]
|
||||
public string QueryGateway()
|
||||
public async ValueTask<string> QueryGateway()
|
||||
{
|
||||
await ValueTask.CompletedTask;
|
||||
return new QueryGatewayHandler().Data;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user