diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..12ceda93
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,4 @@
+[*.cs]
+
+# IDE0022: 使用方法的程序块主体
+csharp_style_expression_bodied_methods = false
diff --git a/Common/Common.csproj b/Common/Common.csproj
index f34b1b3b..7503b45f 100644
--- a/Common/Common.csproj
+++ b/Common/Common.csproj
@@ -15,6 +15,7 @@
+
diff --git a/GameServer/Data/Excel/AvatarConfigExcel.cs b/Common/Data/Excel/AvatarConfigExcel.cs
similarity index 66%
rename from GameServer/Data/Excel/AvatarConfigExcel.cs
rename to Common/Data/Excel/AvatarConfigExcel.cs
index e4cf9404..90f9bd8a 100644
--- a/GameServer/Data/Excel/AvatarConfigExcel.cs
+++ b/Common/Data/Excel/AvatarConfigExcel.cs
@@ -1,10 +1,12 @@
namespace EggLink.DanhengServer.Data.Excel
{
[ResourceEntity("AvatarConfig.json", true)]
- internal class AvatarConfigExcel : ExcelResource
+ public class AvatarConfigExcel : ExcelResource
{
public int AvatarID { get; set; } = 0;
+ public HashName AvatarName { get; set; } = new();
+ public List DefaultSkillTree = [];
public override int GetId()
{
return AvatarID;
diff --git a/Common/Data/Excel/AvatarSkillTreeConfigExcel.cs b/Common/Data/Excel/AvatarSkillTreeConfigExcel.cs
new file mode 100644
index 00000000..f209cb4a
--- /dev/null
+++ b/Common/Data/Excel/AvatarSkillTreeConfigExcel.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Data.Excel
+{
+ [ResourceEntity("AvatarSkillTreeConfig.json")]
+ public class AvatarSkillTreeConfigExcel : ExcelResource
+ {
+
+ public int PointID { get; set; }
+ public int Level { get; set; }
+ public int AvatarID { get; set; }
+ public bool DefaultUnlock { get; set; }
+ public int MaxLevel { get; set; }
+
+ public override int GetId()
+ {
+ return (PointID << 4) + Level;
+ }
+
+ public override void AfterAllDone()
+ {
+ GameData.AvatarConfigData.TryGetValue(AvatarID, out var excel);
+ if (excel != null && DefaultUnlock)
+ {
+ excel.DefaultSkillTree.Add(this);
+ }
+ }
+ }
+}
diff --git a/Common/Data/Excel/MapEntranceExcel.cs b/Common/Data/Excel/MapEntranceExcel.cs
new file mode 100644
index 00000000..295b3a33
--- /dev/null
+++ b/Common/Data/Excel/MapEntranceExcel.cs
@@ -0,0 +1,25 @@
+namespace EggLink.DanhengServer.Data.Excel
+{
+ [ResourceEntity("MapEntrance.json", true)]
+ public class MapEntranceExcel : ExcelResource
+ {
+ public int ID { get; set; }
+ public int PlaneID { get; set; }
+ public int FloorID { get; set; }
+ public int StartGroupID { get; set; }
+ public int StartAnchorID { get; set; }
+
+ public List FinishMainMissionList { get; set; } = [];
+ public List FinishSubMissionList { get; set; } = [];
+
+ public override int GetId()
+ {
+ return ID;
+ }
+
+ public override void Loaded()
+ {
+ GameData.MapEntranceData.Add(ID, this);
+ }
+ }
+}
diff --git a/GameServer/Data/Excel/StageConfigExcel.cs b/Common/Data/Excel/StageConfigExcel.cs
similarity index 88%
rename from GameServer/Data/Excel/StageConfigExcel.cs
rename to Common/Data/Excel/StageConfigExcel.cs
index f124d728..0f08dea1 100644
--- a/GameServer/Data/Excel/StageConfigExcel.cs
+++ b/Common/Data/Excel/StageConfigExcel.cs
@@ -3,7 +3,7 @@
namespace EggLink.DanhengServer.Data.Excel
{
[ResourceEntity("StageConfig.json", false)]
- internal class StageConfigExcel : ExcelResource
+ public class StageConfigExcel : ExcelResource
{
public int StageID { get; set; } = 0;
public HashName StageName { get; set; } = new HashName();
@@ -20,7 +20,7 @@ namespace EggLink.DanhengServer.Data.Excel
}
}
- internal class StageMonsterList
+ public class StageMonsterList
{
public int Monster0 { get; set; } = 0;
public int Monster1 { get; set; } = 0;
@@ -29,7 +29,7 @@ namespace EggLink.DanhengServer.Data.Excel
public int Monster4 { get; set; } = 0;
}
- internal class HashName
+ public class HashName
{
public long Hash { get; set; } = 0;
}
diff --git a/GameServer/Data/ExcelResource.cs b/Common/Data/ExcelResource.cs
similarity index 75%
rename from GameServer/Data/ExcelResource.cs
rename to Common/Data/ExcelResource.cs
index c48af346..0ec48d3f 100644
--- a/GameServer/Data/ExcelResource.cs
+++ b/Common/Data/ExcelResource.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace EggLink.DanhengServer.Data
{
- internal abstract class ExcelResource
+ public abstract class ExcelResource
{
public abstract int GetId();
@@ -17,5 +17,9 @@ namespace EggLink.DanhengServer.Data
public virtual void Finalized()
{
}
+
+ public virtual void AfterAllDone()
+ {
+ }
}
}
diff --git a/GameServer/Data/GameData.cs b/Common/Data/GameData.cs
similarity index 55%
rename from GameServer/Data/GameData.cs
rename to Common/Data/GameData.cs
index 110746a2..f2924c5b 100644
--- a/GameServer/Data/GameData.cs
+++ b/Common/Data/GameData.cs
@@ -3,9 +3,10 @@ using System.Collections.Generic;
namespace EggLink.DanhengServer.Data
{
- internal static class GameData
+ public static class GameData
{
- public static Dictionary AvatarConfigData { get; private set; } = new Dictionary();
- public static Dictionary StageConfigData { get; private set; } = new Dictionary();
+ public static Dictionary AvatarConfigData { get; private set; } = [];
+ public static Dictionary StageConfigData { get; private set; } = [];
+ public static Dictionary MapEntranceData { get; private set; } = [];
}
}
diff --git a/GameServer/Data/ResourceEntity.cs b/Common/Data/ResourceEntity.cs
similarity index 100%
rename from GameServer/Data/ResourceEntity.cs
rename to Common/Data/ResourceEntity.cs
diff --git a/GameServer/Data/ResourceManager.cs b/Common/Data/ResourceManager.cs
similarity index 79%
rename from GameServer/Data/ResourceManager.cs
rename to Common/Data/ResourceManager.cs
index 27b4ff08..7bc29238 100644
--- a/GameServer/Data/ResourceManager.cs
+++ b/Common/Data/ResourceManager.cs
@@ -1,14 +1,13 @@
using System;
using System.IO;
using System.Reflection;
-using EggLink.DanhengServer.Program;
using EggLink.DanhengServer.Util;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace EggLink.DanhengServer.Data
{
- internal class ResourceManager
+ public class ResourceManager
{
public static Logger Logger { get; private set; } = new Logger("ResourceManager");
public static void LoadGameData()
@@ -21,12 +20,12 @@ namespace EggLink.DanhengServer.Data
var classes = Assembly.GetExecutingAssembly().GetTypes(); // Get all classes in the assembly
foreach (var cls in classes)
{
- var attribute = (ResourceEntity)Attribute.GetCustomAttribute(cls, typeof(ResourceEntity));
+ var attribute = (ResourceEntity)Attribute.GetCustomAttribute(cls, typeof(ResourceEntity))!;
if (attribute != null)
{
- var resource = (ExcelResource)Activator.CreateInstance(cls);
- var path = EntryPoint.GetConfig().Path.ResourcePath + "/ExcelOutput/" + attribute.FileName;
+ var resource = (ExcelResource)Activator.CreateInstance(cls)!;
+ var path = ConfigManager.Config.Path.ResourcePath + "/ExcelOutput/" + attribute.FileName;
var file = new FileInfo(path);
if (!file.Exists)
{
@@ -52,7 +51,7 @@ namespace EggLink.DanhengServer.Data
foreach (var item in jArray)
{
var res = JsonConvert.DeserializeObject(item.ToString(), cls);
- ((ExcelResource)res).Loaded();
+ ((ExcelResource?)res)?.Loaded();
count++;
}
}
@@ -71,9 +70,9 @@ namespace EggLink.DanhengServer.Data
var nestedObject = JsonConvert.DeserializeObject(obj.ToString());
// Process only if it's a top-level dictionary, not nested
- if (nestedObject.Count > 0 && nestedObject.First.First.Type != JTokenType.Object)
+ if (nestedObject?.Count > 0 && nestedObject?.First?.First?.Type != JTokenType.Object)
{
- ((ExcelResource)instance).Loaded();
+ ((ExcelResource?)instance)?.Loaded();
}
}
else
@@ -84,9 +83,21 @@ namespace EggLink.DanhengServer.Data
}
}
}
+ resource.Finalized();
+
Logger.Info($"Loaded {count} {cls.Name}s.");
}
}
+ foreach (var cls in classes)
+ {
+ var attribute = (ResourceEntity)Attribute.GetCustomAttribute(cls, typeof(ResourceEntity))!;
+
+ if (attribute != null)
+ {
+ var resource = (ExcelResource)Activator.CreateInstance(cls)!;
+ resource.AfterAllDone();
+ }
+ }
}
}
diff --git a/Common/Database/Account/AccountData.cs b/Common/Database/Account/AccountData.cs
index 705d6289..6cc8ca1a 100644
--- a/Common/Database/Account/AccountData.cs
+++ b/Common/Database/Account/AccountData.cs
@@ -1,62 +1,53 @@
using EggLink.DanhengServer.Util;
using Microsoft.Data.Sqlite;
+using SqlSugar;
namespace EggLink.DanhengServer.Database.Account
{
- [DatabaseEntity("account")]
- public class AccountData(string username, long uid, string comboToken = "", string dispatchToken = "", string permissions = "") : BaseDatabaseData
+ [SugarTable("Account")]
+ public class AccountData() : BaseDatabaseData
{
- public string Username { get; set; } = username;
- public long Uid { get; set; } = uid;
- public string ComboToken { get; set; } = comboToken;
- public string DispatchToken { get; set; } = dispatchToken;
- public string Permissions { get; set; } = permissions; // type: permission1,permission2,permission3...
+ public string? Username { get; set; }
- public static BaseDatabaseData? GetAccountByUserName(string username)
+ [SugarColumn(IsNullable = true)]
+ public string? ComboToken { get; set; }
+
+ [SugarColumn(IsNullable = true)]
+ public string? DispatchToken { get; set; }
+
+ [SugarColumn(IsNullable = true)]
+ public string? Permissions { get; set; } // type: permission1,permission2,permission3...
+
+ public static AccountData? GetAccountByUserName(string username)
{
- var connection = DatabaseHelper.Instance.connection;
- var command = new SqliteCommand("SELECT * FROM account", connection);
- var reader = command.ExecuteReader();
AccountData? result = null;
- while (reader.Read())
+ DatabaseHelper.Instance?.GetAllInstance()?.ForEach((account) =>
{
- if (reader.GetString(0) == username)
+ if (account.Username == username)
{
- result = new(reader.GetString(0), reader.GetInt64(1), reader.GetString(2), reader.GetString(3), reader.GetString(4));
- break;
+ result = account;
}
- }
+ });
return result;
}
- public static BaseDatabaseData? GetAccountByUid(long uid)
+ public static AccountData? GetAccountByUid(long uid)
{
- var connection = DatabaseHelper.Instance.connection;
- var command = new SqliteCommand("SELECT * FROM account", connection);
- var reader = command.ExecuteReader();
- AccountData? result = null;
- while (reader.Read())
- {
- if (reader.GetInt64(1) == uid)
- {
- result = new(reader.GetString(0), reader.GetInt64(1), reader.GetString(2), reader.GetString(3), reader.GetString(4));
- break;
- }
- }
+ AccountData? result = DatabaseHelper.Instance?.GetInstance(uid);
return result;
}
public string GenerateDispatchToken()
{
DispatchToken = Crypto.CreateSessionKey(Uid.ToString());
- ModifyDatabase(Uid, "dispatchToken", DispatchToken);
+ DatabaseHelper.Instance?.UpdateInstance(this);
return DispatchToken;
}
public string GenerateComboToken()
{
ComboToken = Crypto.CreateSessionKey(Uid.ToString());
- ModifyDatabase(Uid, "comboToken", ComboToken);
+ DatabaseHelper.Instance?.UpdateInstance(this);
return ComboToken;
}
}
diff --git a/Common/Database/Account/AccountHelper.cs b/Common/Database/Account/AccountHelper.cs
index 4304e0a8..589b4da9 100644
--- a/Common/Database/Account/AccountHelper.cs
+++ b/Common/Database/Account/AccountHelper.cs
@@ -17,7 +17,7 @@ namespace EggLink.DanhengServer.Database.Account
long newUid = uid;
if (uid == 0)
{
- newUid = 10000; // start from 10000
+ newUid = 10001; // start from 10001
while (AccountData.GetAccountByUid(newUid) != null)
{
newUid++;
@@ -25,8 +25,13 @@ namespace EggLink.DanhengServer.Database.Account
}
var per = ConfigManager.Config.ServerOption.DefaultPermissions;
var perStr = string.Join(",", per);
- var account = new AccountData(username,newUid, permissions: perStr);
- account.SaveToDatabase();
+ var account = new AccountData()
+ {
+ Uid = newUid,
+ Username = username,
+ Permissions = perStr
+ };
+ DatabaseHelper.Instance?.SaveInstance(account);
}
}
}
diff --git a/Common/Database/Avatar/AvatarData.cs b/Common/Database/Avatar/AvatarData.cs
new file mode 100644
index 00000000..8029d3c8
--- /dev/null
+++ b/Common/Database/Avatar/AvatarData.cs
@@ -0,0 +1,97 @@
+using EggLink.DanhengServer.Data.Excel;
+using EggLink.DanhengServer.Proto;
+using SqlSugar;
+
+namespace EggLink.DanhengServer.Database.Avatar
+{
+ [SugarTable("Avatar")]
+ public class AvatarData : BaseDatabaseData
+ {
+ [SugarColumn(IsNullable = true)]
+ public List? Avatars { get; set; }
+
+ public List AssistAvatars { get; set; } = [];
+ public List DisplayAvatars { get; set; } = [];
+ }
+
+ public class AvatarInfo
+ {
+ public int AvatarId { get; set; }
+ public int Level { get; set; }
+ public int Exp { get; set; }
+ public int Promotion { get; set; }
+ public int Rewards { get; set; }
+ public long Timestamp { get; set; }
+ public int CurrentHp { get; set; }
+ public int CurrentSp { get; set; }
+ public int ExtraLineupHp { get; set; }
+ public int ExtraLineupSp { get; set; }
+ public int Rank { get; set; }
+ public Dictionary SkillTree { get; set; } = [];
+ public int EquipId { get; set; } = 0;
+ public Dictionary Relic { get; set; } = [];
+
+ public AvatarConfigExcel Excel;
+
+ public AvatarInfo(AvatarConfigExcel excel)
+ {
+ Excel = excel;
+ SkillTree = [];
+ excel.DefaultSkillTree.ForEach(skill =>
+ {
+ SkillTree.Add(skill.PointID, skill.Level);
+ });
+ }
+
+ public bool HasTakenReward(int promotion)
+ {
+ return (Rewards & (1 << promotion)) != 0;
+ }
+
+ public Proto.Avatar ToProto()
+ {
+ var proto = new Proto.Avatar()
+ {
+ BaseAvatarId = (uint)AvatarId,
+ Level = (uint)Level,
+ Exp = (uint)Exp,
+ Promotion = (uint)Promotion,
+ Rank = (uint)Rank,
+ FirstMetTimestamp = (ulong)Timestamp,
+ };
+
+ foreach (var item in Relic)
+ {
+ proto.EquipRelicList.Add(new EquipRelic()
+ {
+ RelicUniqueId = (uint)item.Value,
+ Slot = (uint)item.Key
+ });
+ }
+
+ if (EquipId != 0)
+ {
+ proto.EquipmentUniqueId = (uint)EquipId;
+ }
+
+ foreach (var skill in SkillTree)
+ {
+ proto.SkilltreeList.Add(new AvatarSkillTree()
+ {
+ PointId = (uint)skill.Key,
+ Level = (uint)skill.Value
+ });
+ }
+
+ for (int i = 0; i < Promotion; i++)
+ {
+ if (HasTakenReward(i))
+ {
+ proto.TakenRewards.Add((uint)i);
+ }
+ }
+
+ return proto;
+ }
+ }
+}
diff --git a/Common/Database/BaseDatabaseData.cs b/Common/Database/BaseDatabaseData.cs
index db5e4f24..43c093ae 100644
--- a/Common/Database/BaseDatabaseData.cs
+++ b/Common/Database/BaseDatabaseData.cs
@@ -1,77 +1,11 @@
using Microsoft.Data.Sqlite;
+using SqlSugar;
namespace EggLink.DanhengServer.Database
{
public abstract class BaseDatabaseData
{
- public void SaveToDatabase()
- {
- var connection = DatabaseHelper.Instance.connection;
- var attributes = GetType().GetCustomAttributes(true);
- string tableName = "";
- foreach ( var attribute in attributes )
- {
- if (attribute is DatabaseEntity)
- {
- tableName = (attribute as DatabaseEntity).TableName;
- break;
- }
- }
- var command = new SqliteCommand($"INSERT INTO {tableName} (", connection);
- var properties = GetType().GetProperties();
- foreach (var property in properties)
- {
- command.CommandText += $"{property.Name}, ";
- }
- command.CommandText = command.CommandText[..^2];
- command.CommandText += ") VALUES (";
- foreach (var property in properties)
- {
- command.CommandText += $"\"{property.GetValue(this)}\", ";
- }
- command.CommandText = command.CommandText[..^2];
- command.CommandText += ")";
- command.ExecuteNonQuery();
- }
-
- public void ModifyDatabase(long uid, string property, string value)
- {
- var connection = DatabaseHelper.Instance.connection;
- var attributes = GetType().GetCustomAttributes(true);
- string tableName = "";
- foreach ( var attribute in attributes )
- {
- if (attribute is DatabaseEntity)
- {
- tableName = (attribute as DatabaseEntity).TableName;
- break;
- }
- }
- var command = new SqliteCommand($"UPDATE {tableName} SET \"{property}\" = \"{value}\" WHERE UID = {uid};", connection);
- command.ExecuteNonQuery();
- }
-
- public void DeleteFromDatabase()
- {
- var connection = DatabaseHelper.Instance.connection;
- var attributes = GetType().GetCustomAttributes(true);
- string tableName = "";
- foreach ( var attribute in attributes )
- {
- if (attribute is DatabaseEntity)
- {
- tableName = (attribute as DatabaseEntity).TableName;
- break;
- }
- }
- var command = new SqliteCommand($"DELETE FROM {tableName} WHERE ", connection);
- var properties = GetType().GetProperties();
- foreach (var property in properties)
- {
- command.CommandText += $"{property.Name} = {property.GetValue(this)} AND ";
- }
- command.CommandText = command.CommandText[..^5];
- command.ExecuteNonQuery();
- }
+ [SugarColumn(IsPrimaryKey = true)]
+ public long Uid { get; set; }
}
}
diff --git a/Common/Database/DatabaseEntity.cs b/Common/Database/DatabaseEntity.cs
deleted file mode 100644
index c4dd0e5a..00000000
--- a/Common/Database/DatabaseEntity.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace EggLink.DanhengServer.Database
-{
- [AttributeUsage(AttributeTargets.Class)]
- public class DatabaseEntity(string tableName) : Attribute
- {
- public string TableName { get; set; } = tableName;
- }
-}
diff --git a/Common/Database/DatabaseHelper.cs b/Common/Database/DatabaseHelper.cs
index 6a3ce33f..f8b7096a 100644
--- a/Common/Database/DatabaseHelper.cs
+++ b/Common/Database/DatabaseHelper.cs
@@ -1,6 +1,8 @@
using EggLink.DanhengServer.Configuration;
+using EggLink.DanhengServer.Database.Account;
using EggLink.DanhengServer.Util;
using Microsoft.Data.Sqlite;
+using SqlSugar;
using System.Reflection;
namespace EggLink.DanhengServer.Database
@@ -9,8 +11,8 @@ namespace EggLink.DanhengServer.Database
{
public Logger logger = new("Database");
public ConfigContainer config = ConfigManager.Config;
- public SqliteConnection connection;
- public static DatabaseHelper Instance;
+ public static SqlSugarScope? sqlSugarScope;
+ public static DatabaseHelper? Instance;
public DatabaseHelper()
{
@@ -19,7 +21,12 @@ namespace EggLink.DanhengServer.Database
{
f.Directory.Create();
}
- connection = new SqliteConnection($"Data Source={f.FullName};");
+ sqlSugarScope = new(new ConnectionConfig()
+ {
+ ConnectionString = $"Data Source={f.FullName};",
+ DbType = DbType.Sqlite,
+ IsAutoCloseConnection = true,
+ });
Instance = this;
}
public void Initialize()
@@ -36,70 +43,65 @@ namespace EggLink.DanhengServer.Database
}
}
- public void InitializeSqlite()
+ public static void InitializeSqlite()
{
- SQLitePCL.Batteries.Init();
- connection.Open();
- var classes = Assembly.GetExecutingAssembly().GetTypes();
- foreach (var cls in classes) {
- var attribute = (DatabaseEntity)Attribute.GetCustomAttribute(cls, typeof(DatabaseEntity));
- if (attribute != null)
- {
- var tableName = attribute.TableName;
- var createTable = $"CREATE TABLE IF NOT EXISTS {tableName} (";
- var properties = cls.GetProperties();
- foreach (var property in properties)
- {
- createTable += $"{property.Name} {GetSqliteType(property.PropertyType)}, ";
- }
- createTable = createTable.Substring(0, createTable.Length - 2);
- createTable += ")";
- var command = new SqliteCommand(createTable, connection);
- command.ExecuteNonQuery();
- }
+ var baseType = typeof(BaseDatabaseData);
+ var assembly = typeof(BaseDatabaseData).Assembly;
+ var types = assembly.GetTypes().Where(t => t.IsSubclassOf(baseType));
+ foreach (var type in types)
+ {
+ typeof(DatabaseHelper).GetMethod("InitializeSqliteTable")?.MakeGenericMethod(type).Invoke(null, null);
}
}
- private string GetSqliteType(Type propertyType)
+ public static void InitializeSqliteTable() where T : class, new()
{
- if (propertyType == typeof(int))
+ try
{
- return "INTEGER";
- }
- else if (propertyType == typeof(string))
+ sqlSugarScope?.Queryable().ToList();
+ } catch
{
- return "TEXT";
- }
- else if (propertyType == typeof(bool))
- {
- return "INTEGER";
- }
- else if (propertyType == typeof(float))
- {
- return "REAL";
- }
- else if (propertyType == typeof(double))
- {
- return "REAL";
- }
- else if (propertyType == typeof(long))
- {
- return "INTEGER";
- }
- else if (propertyType == typeof(byte[]))
- {
- return "BLOB";
- }
- else
- {
- logger.Error($"Unsupported type {propertyType}");
- return "TEXT";
+ sqlSugarScope?.CodeFirst.InitTables();
}
}
- public void Close()
+ public T? GetInstance(long uid) where T : class, new()
{
- connection.Close();
+ try
+ {
+ return sqlSugarScope?.Queryable().Where(it => (it as BaseDatabaseData).Uid == uid).First();
+ } catch
+ {
+ logger.Error("Unsupported type");
+ return null;
+ }
+ }
+
+ public List? GetAllInstance() where T : class, new()
+ {
+ try
+ {
+ return sqlSugarScope?.Queryable().ToList();
+ } catch
+ {
+ logger.Error("Unsupported type");
+ return null;
+ }
+ }
+
+ public void SaveInstance(T instance) where T : class, new()
+ {
+ sqlSugarScope?.Insertable(instance).ExecuteCommand();
+ }
+
+ public void UpdateInstance(T instance) where T : class, new()
+ {
+ sqlSugarScope?.Updateable(instance).ExecuteCommand();
+ }
+
+ public void DeleteInstance(T instance) where T : class, new()
+ {
+ sqlSugarScope?.Deleteable(instance).ExecuteCommand();
}
}
}
diff --git a/Common/Database/Inventory/InventoryData.cs b/Common/Database/Inventory/InventoryData.cs
new file mode 100644
index 00000000..52489704
--- /dev/null
+++ b/Common/Database/Inventory/InventoryData.cs
@@ -0,0 +1,95 @@
+using EggLink.DanhengServer.Proto;
+using SqlSugar;
+
+namespace EggLink.DanhengServer.Database.Inventory
+{
+ public class InventoryData : BaseDatabaseData
+ {
+ [SugarColumn(IsJson = true)]
+ public List MaterialItems { get; set; } = [];
+ [SugarColumn(IsJson = true)]
+ public List EquipmentItems { get; set; } = [];
+ [SugarColumn(IsJson = true)]
+ public List RelicItems { get; set; } = [];
+ }
+
+ public class ItemData
+ {
+ [SugarColumn(IsPrimaryKey = true)]
+ public int UniqueId { get; set; }
+ public int ItemId { get; set; }
+ public int Count { get; set; }
+ public int Level { get; set; }
+ public int Exp { get; set; }
+ public int TotalExp { get; set; }
+ public int Promotion { get; set; }
+ public int Rank { get; set; } // Superimpose
+ public bool Locked { get; set; }
+ public bool Discarded { get; set; }
+
+ public int MainAffix { get; set; }
+ public List SubAffixes { get; set; } = [];
+
+ public int EquipAvatar { get; set; }
+
+ public Material ToMaterialProto()
+ {
+ return new()
+ {
+ Tid = (uint)ItemId,
+ Num = (uint)Count,
+ };
+ }
+
+ public Relic ToRelicProto()
+ {
+ Relic relic = new()
+ {
+ Tid = (uint)ItemId,
+ UniqueId = (uint)UniqueId,
+ Level = (uint)Level,
+ IsProtected = Locked,
+ IsDiscarded = Discarded,
+ BaseAvatarId = (uint)EquipAvatar,
+ MainAffixId = (uint)MainAffix,
+ };
+ if (SubAffixes.Count >= 1)
+ {
+ foreach (var subAffix in SubAffixes)
+ {
+ relic.SubAffixList.Add(subAffix.ToProto());
+ }
+ }
+ return relic;
+ }
+ public Equipment ToEquipmentProto()
+ {
+ return new()
+ {
+ Tid = (uint)ItemId,
+ UniqueId = (uint)UniqueId,
+ Level = (uint)Level,
+ Exp = (uint)Exp,
+ IsProtected = Locked,
+ Promotion = (uint)Promotion,
+ Rank = (uint)Rank,
+ BaseAvatarId = (uint)EquipAvatar
+ };
+ }
+ }
+
+ public class ItemSubAffix
+ {
+ public int Id { get; set; } // Affix id
+
+ public int Count { get; set; }
+ public int Step { get; set; }
+
+ public RelicAffix ToProto() => new()
+ {
+ AffixId = (uint)Id,
+ Cnt = (uint)Count,
+ Step = (uint)Step
+ };
+ }
+}
diff --git a/Common/Database/Lineup/LineupData.cs b/Common/Database/Lineup/LineupData.cs
new file mode 100644
index 00000000..26d30223
--- /dev/null
+++ b/Common/Database/Lineup/LineupData.cs
@@ -0,0 +1,28 @@
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Database.Lineup
+{
+ [SugarTable("Lineup")]
+ public class LineupData : BaseDatabaseData
+ {
+ public int CurLineup { get; set; } // index of current lineup
+ public string? Lineups { get; set; } // 9 * 4
+ }
+
+ public class LineupInfo
+ {
+ public string? Name { get; set; }
+ public int LineupType { get; set; }
+ public List? BaseAvatars { get; set; }
+ }
+
+ public class LineupInfoJson
+ {
+ public Dictionary? Lineups { get; set; } = []; // 9 * 4
+ }
+}
diff --git a/Common/Database/Player/PlayerData.cs b/Common/Database/Player/PlayerData.cs
new file mode 100644
index 00000000..d0fa0f35
--- /dev/null
+++ b/Common/Database/Player/PlayerData.cs
@@ -0,0 +1,48 @@
+using EggLink.DanhengServer.Enums;
+using EggLink.DanhengServer.Proto;
+using EggLink.DanhengServer.Util;
+using SqlSugar;
+
+namespace EggLink.DanhengServer.Database.Player
+{
+ [SugarTable("Player")]
+ public class PlayerData : BaseDatabaseData
+ {
+ public string? Name { get; set; }
+ public string? Signature { get; set; }
+ public int Birthday { get; set; }
+ public int CurBasicType { get; set; }
+ public int HeadIcon { get; set; }
+ public int PhoneTheme { get; set; }
+ public int ChatBubble { get; set; }
+ public int CurrentBgm { get; set; }
+ public Gender? CurrentGender { get; set; }
+ public int Level { get; set; }
+ public int Exp { get; set; }
+ public int WorldLevel { get; set; }
+ public int Scoin { get; set; } // Credits
+ public int Hcoin { get; set; } // Jade
+ public int Mcoin { get; set; } // Crystals
+ public int TalentPoints { get; set; } // Rogue talent points
+
+ public int Stamina { get; set; }
+ public double StaminaReserve { get; set; }
+ public long NextStaminaRecover { get; set; }
+
+ [SugarColumn(IsNullable = true)]
+ public Position? Pos { get; set; }
+ [SugarColumn(IsNullable = true)]
+ public Position? Rot { get; set; }
+ [SugarColumn(IsNullable = true)]
+ public int PlaneId { get; set; }
+ [SugarColumn(IsNullable = true)]
+ public int FloorId { get; set; }
+ [SugarColumn(IsNullable = true)]
+ public int EntryId { get; set; }
+
+ [SugarColumn(IsNullable = true)]
+ public long LastActiveTime { get; set; }
+
+
+ }
+}
diff --git a/Common/Database/Player/PlayerUnlockData.cs b/Common/Database/Player/PlayerUnlockData.cs
new file mode 100644
index 00000000..36910e52
--- /dev/null
+++ b/Common/Database/Player/PlayerUnlockData.cs
@@ -0,0 +1,9 @@
+namespace EggLink.DanhengServer.Database.Player
+{
+ public class PlayerUnlockData : BaseDatabaseData
+ {
+ public List HeadIcons { get; set; } = [];
+ public List ChatBubbles { get; set; } = [];
+ public List PhoneThemes { get; set; } = [];
+ }
+}
diff --git a/GameServer/Game/Player/Player.cs b/Common/Enums/PlayerGender.cs
similarity index 50%
rename from GameServer/Game/Player/Player.cs
rename to Common/Enums/PlayerGender.cs
index 1ac1afec..06e6df47 100644
--- a/GameServer/Game/Player/Player.cs
+++ b/Common/Enums/PlayerGender.cs
@@ -4,13 +4,11 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace EggLink.DanhengServer.Game.Player
+namespace EggLink.DanhengServer.Enums
{
- public class Player
+ public enum PlayerGender
{
- public async Task OnLogoutAsync()
- {
-
- }
+ PLAYER_MALE = 0,
+ PLAYER_FEMALE = 1,
}
}
diff --git a/GameServer/Enums/SessionState.cs b/Common/Enums/SessionState.cs
similarity index 76%
rename from GameServer/Enums/SessionState.cs
rename to Common/Enums/SessionState.cs
index 4414cfd2..bb0c2b09 100644
--- a/GameServer/Enums/SessionState.cs
+++ b/Common/Enums/SessionState.cs
@@ -1,4 +1,4 @@
-namespace EggLink.DanhengServer.Enums
+namespace EggLink.DanhengServer.Common.Enums
{
public enum SessionState
{
diff --git a/Common/Util/GameConstants.cs b/Common/Util/GameConstants.cs
new file mode 100644
index 00000000..82d9ae44
--- /dev/null
+++ b/Common/Util/GameConstants.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Util
+{
+ public static class GameConstants
+ {
+ public const int MATERIAL_HCOIN_ID = 1; // Material id for jades. DO NOT CHANGE
+ public const int MATERIAL_COIN_ID = 2; // Material id for credits. DO NOT CHANGE
+ public const int TRAILBLAZER_EXP_ID = 22;
+ public const int RELIC_REMAINS_ID = 235;
+
+ public const int INVENTORY_MAX_EQUIPMENT = 1500;
+ public const int INVENTORY_MAX_RELIC = 1500;
+ public const int INVENTORY_MAX_MATERIAL = 2000;
+ }
+}
diff --git a/Common/Util/Logger.cs b/Common/Util/Logger.cs
index 5efbd8d8..98f83528 100644
--- a/Common/Util/Logger.cs
+++ b/Common/Util/Logger.cs
@@ -107,10 +107,9 @@ namespace EggLink.DanhengServer.Util
}
}
- public static Logger GetByClassName()
- {
- return new Logger(new StackTrace().GetFrame(1).GetMethod().ReflectedType.Name);
- }
+#pragma warning disable CS8602
+ public static Logger GetByClassName() => new(new StackTrace().GetFrame(1).GetMethod().ReflectedType.Name);
+#pragma warning restore CS8602
}
public enum LoggerLevel
diff --git a/Common/Util/Position.cs b/Common/Util/Position.cs
new file mode 100644
index 00000000..b77fcc14
--- /dev/null
+++ b/Common/Util/Position.cs
@@ -0,0 +1,121 @@
+using EggLink.DanhengServer.Proto;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Util
+{
+ public class Position
+ {
+ public int X { get; set; }
+ public int Y { get; set; }
+ public int Z { get; set; }
+
+ public Position(int x, int y, int z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ }
+
+ public Position(Vector vector)
+ {
+ X = vector.X;
+ Y = vector.Y;
+ Z = vector.Z;
+ }
+
+ public Position()
+ {
+ X = 0;
+ Y = 0;
+ Z = 0;
+ }
+
+ public Position(Position position)
+ {
+ X = position.X;
+ Y = position.Y;
+ Z = position.Z;
+ }
+
+ public void Set(int x, int y, int z)
+ {
+ X = x;
+ Y = y;
+ Z = z;
+ }
+
+ public void Set(Position position)
+ {
+ X = position.X;
+ Y = position.Y;
+ Z = position.Z;
+ }
+
+ public void Set(Vector vector)
+ {
+ X = vector.X;
+ Y = vector.Y;
+ Z = vector.Z;
+ }
+
+ public void Add(int x, int y, int z)
+ {
+ X += x;
+ Y += y;
+ Z += z;
+ }
+
+ public void Add(Position position)
+ {
+ X += position.X;
+ Y += position.Y;
+ Z += position.Z;
+ }
+
+ public void Sub(int x, int y, int z)
+ {
+ X -= x;
+ Y -= y;
+ Z -= z;
+ }
+
+ public void Sub(Position position)
+ {
+ X -= position.X;
+ Y -= position.Y;
+ Z -= position.Z;
+ }
+
+ public void Mul(int x, int y, int z)
+ {
+ X *= x;
+ Y *= y;
+ Z *= z;
+ }
+
+ public void Mul(Position position)
+ {
+ X *= position.X;
+ Y *= position.Y;
+ Z *= position.Z;
+ }
+
+ public void Div(int x, int y, int z)
+ {
+ X /= x;
+ Y /= y;
+ Z /= z;
+ }
+
+ public void Div(Position position)
+ {
+ X /= position.X;
+ Y /= position.Y;
+ Z /= position.Z;
+ }
+ }
+}
diff --git a/DanhengServer.sln b/DanhengServer.sln
index 7a646f12..66f9e59b 100644
--- a/DanhengServer.sln
+++ b/DanhengServer.sln
@@ -14,6 +14,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决
README.md = README.md
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0C822679-4BCC-497A-AF15-F441EC750CCE}"
+ ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
diff --git a/GameServer/Game/Avatar/AvatarManager.cs b/GameServer/Game/Avatar/AvatarManager.cs
new file mode 100644
index 00000000..71455692
--- /dev/null
+++ b/GameServer/Game/Avatar/AvatarManager.cs
@@ -0,0 +1,56 @@
+using EggLink.DanhengServer.Data;
+using EggLink.DanhengServer.Data.Excel;
+using EggLink.DanhengServer.Database;
+using EggLink.DanhengServer.Database.Avatar;
+using EggLink.DanhengServer.Game.Player;
+
+namespace EggLink.DanhengServer.Game.Avatar
+{
+ public class AvatarManager : BasePlayerManager
+ {
+ public AvatarData AvatarData { get; private set; }
+
+ public AvatarManager(PlayerInstance player) : base(player)
+ {
+ var avatars = DatabaseHelper.Instance?.GetInstance(player.Uid);
+ if (avatars == null)
+ {
+ AvatarData = new()
+ {
+ Uid = player.Uid,
+ Avatars = [],
+ };
+ DatabaseHelper.Instance?.SaveInstance(AvatarData);
+ }
+ else
+ {
+ AvatarData = avatars;
+ }
+ }
+
+ public void AddAvatar(int avatarId)
+ {
+ GameData.AvatarConfigData.TryGetValue(avatarId, out AvatarConfigExcel? avatarExcel);
+ if (avatarExcel == null)
+ {
+ return;
+ }
+ var avatar = new AvatarInfo(avatarExcel)
+ {
+ AvatarId = avatarId,
+ Level = 1,
+ Timestamp = DateTime.Now.Ticks / TimeSpan.TicksPerSecond,
+ CurrentHp = 10000,
+ CurrentSp = 0
+ };
+
+ if (AvatarData.Avatars == null)
+ {
+ AvatarData.Avatars = [];
+ }
+
+ AvatarData.Avatars.Add(avatar);
+ DatabaseHelper.Instance?.UpdateInstance(AvatarData);
+ }
+ }
+}
diff --git a/GameServer/Game/BasePlayerManager.cs b/GameServer/Game/BasePlayerManager.cs
new file mode 100644
index 00000000..a6fcde69
--- /dev/null
+++ b/GameServer/Game/BasePlayerManager.cs
@@ -0,0 +1,14 @@
+using EggLink.DanhengServer.Game.Player;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Game
+{
+ public class BasePlayerManager(PlayerInstance player)
+ {
+ public PlayerInstance Player { get; private set; } = player;
+ }
+}
diff --git a/GameServer/Game/Inventory/InventoryManager.cs b/GameServer/Game/Inventory/InventoryManager.cs
new file mode 100644
index 00000000..d4a0d14c
--- /dev/null
+++ b/GameServer/Game/Inventory/InventoryManager.cs
@@ -0,0 +1,26 @@
+using EggLink.DanhengServer.Database;
+using EggLink.DanhengServer.Database.Inventory;
+using EggLink.DanhengServer.Game.Player;
+
+namespace EggLink.DanhengServer.Game.Inventory
+{
+ public class InventoryManager : BasePlayerManager
+ {
+ public InventoryData Data;
+ public InventoryManager(PlayerInstance player) : base(player)
+ {
+ var inventory = DatabaseHelper.Instance?.GetInstance(player.Uid);
+ if (inventory == null)
+ {
+ DatabaseHelper.Instance?.SaveInstance(new InventoryData()
+ {
+ Uid = player.Uid,
+ });
+ inventory = DatabaseHelper.Instance?.GetInstance(player.Uid);
+ }
+ Data = inventory!;
+ }
+
+
+ }
+}
diff --git a/GameServer/Game/Lineup/LineupManager.cs b/GameServer/Game/Lineup/LineupManager.cs
new file mode 100644
index 00000000..a2e09285
--- /dev/null
+++ b/GameServer/Game/Lineup/LineupManager.cs
@@ -0,0 +1,95 @@
+using EggLink.DanhengServer.Database;
+using EggLink.DanhengServer.Database.Lineup;
+using EggLink.DanhengServer.Game.Player;
+using Newtonsoft.Json;
+
+namespace EggLink.DanhengServer.Game.Lineup
+{
+ public class LineupManager : BasePlayerManager
+ {
+ public LineupData LineupData { get; private set; }
+ public LineupInfoJson LineupInfoJson { get; private set; }
+
+ public LineupManager(PlayerInstance player) : base(player)
+ {
+ var lineup = DatabaseHelper.Instance?.GetInstance(player.Uid);
+ if (lineup == null)
+ {
+ LineupData = new()
+ {
+ Uid = player.Uid,
+ CurLineup = 0,
+ Lineups = "{}",
+ };
+ DatabaseHelper.Instance?.SaveInstance(LineupData);
+ }
+ else
+ {
+ LineupData = lineup;
+ }
+ LineupInfoJson = JsonConvert.DeserializeObject(LineupData.Lineups ?? "{}") ?? new();
+ }
+
+ public LineupInfo? GetLineup(int lineupIndex)
+ {
+ if (LineupData.Lineups == null)
+ {
+ return null;
+ }
+ if (lineupIndex < 0 || lineupIndex >= LineupInfoJson.Lineups?.Count)
+ {
+ return null;
+ }
+ return LineupInfoJson.Lineups?[lineupIndex];
+ }
+
+ public LineupInfo? GetCurLineup()
+ {
+ return GetLineup(LineupData.CurLineup);
+ }
+
+ public void SetCurLineup(int lineupIndex)
+ {
+ if (lineupIndex < 0 || lineupIndex >= LineupInfoJson.Lineups?.Count)
+ {
+ return;
+ }
+ LineupData.CurLineup = lineupIndex;
+ DatabaseHelper.Instance?.UpdateInstance(LineupData);
+ }
+
+ public void AddAvatar(int lineupIndex, int avatarId)
+ {
+ if (lineupIndex < 0 || LineupData == null)
+ {
+ return;
+ }
+ if (LineupData.Lineups == null)
+ {
+ LineupData.Lineups = "";
+ }
+ LineupInfo? lineup = null;
+ LineupInfoJson.Lineups?.TryGetValue(lineupIndex, out lineup);
+ if (lineup == null)
+ {
+ lineup = new()
+ {
+ Name = "Lineup " + lineupIndex,
+ LineupType = 0,
+ BaseAvatars = [avatarId],
+ };
+ LineupInfoJson.Lineups?.Add(lineupIndex, lineup);
+ } else
+ {
+ lineup.BaseAvatars?.Add(avatarId);
+ }
+ LineupData.Lineups = JsonConvert.SerializeObject(LineupInfoJson);
+ DatabaseHelper.Instance?.UpdateInstance(LineupData!);
+ }
+
+ public void AddAvatarToCurTeam(int avatarId)
+ {
+ AddAvatar(LineupData.CurLineup, avatarId);
+ }
+ }
+}
diff --git a/GameServer/Game/Player/PlayerInstance.cs b/GameServer/Game/Player/PlayerInstance.cs
new file mode 100644
index 00000000..a460e3c3
--- /dev/null
+++ b/GameServer/Game/Player/PlayerInstance.cs
@@ -0,0 +1,138 @@
+using EggLink.DanhengServer.Database;
+using EggLink.DanhengServer.Database.Player;
+using EggLink.DanhengServer.Enums;
+using EggLink.DanhengServer.Game.Avatar;
+using EggLink.DanhengServer.Game.Inventory;
+using EggLink.DanhengServer.Game.Lineup;
+using EggLink.DanhengServer.Proto;
+using EggLink.DanhengServer.Server;
+using EggLink.DanhengServer.Server.Packet;
+using EggLink.DanhengServer.Server.Packet.Send.Player;
+
+namespace EggLink.DanhengServer.Game.Player
+{
+ public class PlayerInstance(PlayerData data)
+ {
+ public PlayerData Data { get; set; } = data;
+ public ushort Uid { get; set; }
+ public Connection? Connection { get; set; }
+ public bool Initialized { get; set; } = false;
+
+ #region Managers
+
+ public AvatarManager AvatarManager { get; private set; }
+ public LineupManager LineupManager { get; private set; }
+ public InventoryManager InventoryManager { get; private set; }
+
+ #endregion
+
+ #region Datas
+
+ public PlayerUnlockData PlayerUnlockData { get; private set; }
+
+ #endregion
+
+ public PlayerInstance() : this(new PlayerData())
+ {
+ // new player
+ Data.Name = "无名客"; // Trailblazer in EN TODO: Add localization
+ Data.Signature = "";
+ Data.Birthday = 0;
+ Data.CurBasicType = 8001;
+ Data.HeadIcon = 208001;
+ Data.PhoneTheme = 221000;
+ Data.ChatBubble = 220000;
+ Data.CurrentBgm = 210000;
+ Data.CurrentGender = Gender.Man;
+ Data.Stamina = 240;
+ Data.StaminaReserve = 0;
+ Data.NextStaminaRecover = DateTime.Now.Millisecond;
+ Data.Level = 1;
+ Data.Exp = 0;
+ Data.WorldLevel = 0;
+ Data.Scoin = 0;
+ Data.Hcoin = 0;
+ Data.Mcoin = 0;
+ Data.TalentPoints = 0;
+
+ InitialPlayerManager();
+
+ AddAvatar(1005);
+ LineupManager.SetCurLineup(0);
+ LineupManager.AddAvatarToCurTeam(1005);
+ Initialized = true;
+ }
+
+ private void InitialPlayerManager()
+ {
+ Uid = (ushort)Data.Uid;
+ AvatarManager = new(this);
+ LineupManager = new(this);
+ InventoryManager = new(this);
+
+ var unlock = DatabaseHelper.Instance?.GetInstance(Uid);
+ if (unlock == null)
+ {
+ DatabaseHelper.Instance?.SaveInstance(new PlayerUnlockData()
+ {
+ Uid = Uid,
+ });
+ unlock = DatabaseHelper.Instance?.GetInstance(Uid);
+ }
+ PlayerUnlockData = unlock!;
+ }
+
+
+
+ #region Network
+ public void OnLogin()
+ {
+ if (!Initialized)
+ {
+ InitialPlayerManager();
+ }
+
+ SendPacket(new PacketStaminaInfoScNotify(this));
+
+ }
+
+ public async Task OnLogoutAsync()
+ {
+
+ }
+
+ public void SendPacket(BasePacket packet)
+ {
+ Connection?.SendPacket(packet);
+ }
+ #endregion
+
+ #region Extra
+
+ public void AddAvatar(int avatarId)
+ {
+ AvatarManager.AddAvatar(avatarId);
+ }
+
+ #endregion
+
+ #region Proto
+
+ public PlayerBasicInfo ToProto()
+ {
+ return new()
+ {
+ Nickname = Data.Name,
+ Level = (uint)Data.Level,
+ Exp = (uint)Data.Exp,
+ WorldLevel = (uint)Data.WorldLevel,
+ Scoin = (uint)Data.Scoin,
+ Hcoin = (uint)Data.Hcoin,
+ Mcoin = (uint)Data.Mcoin,
+ Stamina = (uint)Data.Stamina,
+ };
+ }
+
+ #endregion
+ }
+}
diff --git a/GameServer/Game/Scene/SceneInstance.cs b/GameServer/Game/Scene/SceneInstance.cs
new file mode 100644
index 00000000..7ebe8670
--- /dev/null
+++ b/GameServer/Game/Scene/SceneInstance.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Game.Scene
+{
+ public class SceneInstance
+ {
+ }
+}
diff --git a/GameServer/GameServer.csproj b/GameServer/GameServer.csproj
index 12e34365..6840fba8 100644
--- a/GameServer/GameServer.csproj
+++ b/GameServer/GameServer.csproj
@@ -16,11 +16,9 @@
-
-
@@ -31,18 +29,16 @@
-
-
-
+
diff --git a/GameServer/Program/EntryPoint.cs b/GameServer/Program/EntryPoint.cs
index 5a4a8267..cd250410 100644
--- a/GameServer/Program/EntryPoint.cs
+++ b/GameServer/Program/EntryPoint.cs
@@ -3,7 +3,6 @@ using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Configuration;
using EggLink.DanhengServer.WebServer;
using EggLink.DanhengServer.Database;
-using System.Runtime.InteropServices;
using EggLink.DanhengServer.Server;
using EggLink.DanhengServer.Server.Packet;
diff --git a/GameServer/Server/Connection.cs b/GameServer/Server/Connection.cs
index cff7df81..19f670fe 100644
--- a/GameServer/Server/Connection.cs
+++ b/GameServer/Server/Connection.cs
@@ -1,7 +1,8 @@
using System.Buffers;
using System.Net;
+using System.Net.Sockets;
using System.Reflection;
-using EggLink.DanhengServer.Enums;
+using EggLink.DanhengServer.Common.Enums;
using EggLink.DanhengServer.Game.Player;
using EggLink.DanhengServer.KcpSharp;
using EggLink.DanhengServer.Program;
@@ -21,16 +22,14 @@ public partial class Connection
private readonly CancellationTokenSource CancelToken;
public readonly IPEndPoint RemoteEndPoint;
public SessionState State { get; set; } = SessionState.INACTIVE;
- private bool UseSecretKey { get; set; } = false;
- private byte[] SecretKey = new byte[0x1000];
- public Player? Player { get; set; }
+ public PlayerInstance? Player { get; set; }
public uint ClientTime { get; private set; }
public long LastPingTime { get; private set; }
private uint LastClientSeq = 10;
public static readonly List BANNED_PACKETS = [];
- private static Logger Logger = new("GameServer");
+ private static readonly Logger Logger = new("GameServer");
#if DEBUG
- private static uint LogIndex = 0;
+ private static readonly Dictionary LogMap = [];
#endif
public Connection(KcpConversation conversation, IPEndPoint remote)
{
@@ -38,11 +37,14 @@ public partial class Connection
RemoteEndPoint = remote;
CancelToken = new CancellationTokenSource();
Start();
+#if DEBUG
+ JsonConvert.DeserializeObject(File.ReadAllText("LogMap.json")).Properties().ToList().ForEach(x => LogMap.Add(x.Name, x.Value.ToString()));
+#endif
}
private async void Start()
{
- Logger.Info($"New connection to {RemoteEndPoint} created with conversation id {Conversation.ConversationId}");
+ Logger.Info($"New connection from {RemoteEndPoint}.");
State = SessionState.WAITING_FOR_TOKEN;
await ReceiveLoop();
}
@@ -72,14 +74,20 @@ public partial class Connection
#if DEBUG
public static void LogPacket(string sendOrRecv, ushort opcode, byte[] payload)
{
- //Logger.DebugWriteLine($"{sendOrRecv}: {Enum.GetName(typeof(OpCode), opcode)}({opcode})\r\n{Convert.ToHexString(payload)}");
- Type? typ = AppDomain.CurrentDomain.GetAssemblies().
- SingleOrDefault(assembly => assembly.GetName().Name == "Shared").GetTypes().First(t => t.Name == $"{Enum.GetName(typeof(CmdId), opcode)}"); //get the type using the packet name
- MessageDescriptor? descriptor = (MessageDescriptor)typ.GetProperty("Descriptor", BindingFlags.Public | BindingFlags.Static).GetValue(null, null); // get the static property Descriptor
- IMessage? packet = descriptor.Parser.ParseFrom(payload);
- JsonFormatter? formatter = JsonFormatter.Default;
- string? asJson = formatter.Format(packet);
- Logger.Debug($"{sendOrRecv}: {Enum.GetName(typeof(CmdId), opcode)}({opcode})\r\n{asJson}");
+ try
+ {
+ //Logger.DebugWriteLine($"{sendOrRecv}: {Enum.GetName(typeof(OpCode), opcode)}({opcode})\r\n{Convert.ToHexString(payload)}");
+ Type? typ = AppDomain.CurrentDomain.GetAssemblies().
+ SingleOrDefault(assembly => assembly.GetName().Name == "Common").GetTypes().First(t => t.Name == $"{LogMap[opcode.ToString()]}"); //get the type using the packet name
+ MessageDescriptor? descriptor = (MessageDescriptor)typ.GetProperty("Descriptor", BindingFlags.Public | BindingFlags.Static).GetValue(null, null); // get the static property Descriptor
+ IMessage? packet = descriptor.Parser.ParseFrom(payload);
+ JsonFormatter? formatter = JsonFormatter.Default;
+ string? asJson = formatter.Format(packet);
+ Logger.Debug($"{sendOrRecv}: {LogMap[opcode.ToString()]}({opcode})\r\n{asJson}");
+ } catch (Exception e)
+ {
+ Logger.Debug($"{sendOrRecv}: {LogMap[opcode.ToString()]}({opcode})");
+ }
}
#endif
@@ -131,8 +139,6 @@ public partial class Connection
{
byte[] gamePacket = data.ToArray();
- // Decrypt and turn back into a packet
- //Crypto.Xor(gamePacket, UseSecretKey ? SecretKey : Crypto.DISPATCH_KEY);
await using MemoryStream? ms = new(gamePacket);
using BinaryReader? br = new(ms);
@@ -159,8 +165,10 @@ public partial class Connection
uint payloadLength = br.ReadUInt32BE();
byte[] header = br.ReadBytes(headerLength);
byte[] payload = br.ReadBytes((int)payloadLength);
-
- await HandlePacketAsync(opcode, header, payload);
+#if DEBUG
+ LogPacket("Recv", opcode, payload);
+#endif
+ HandlePacket(opcode, header, payload);
}
}
@@ -174,7 +182,7 @@ public partial class Connection
}
}
- private async Task HandlePacketAsync(ushort opcode, byte[] header, byte[] payload)
+ private bool HandlePacket(ushort opcode, byte[] header, byte[] payload)
{
// Find the Handler for this opcode
Handler? handler = EntryPoint.HandlerManager.GetHandler(opcode);
@@ -185,7 +193,7 @@ public partial class Connection
SessionState state = State;
switch ((int)opcode)
{
- case CmdId.PlayerGetTokenCsReq:
+ case CmdIds.PlayerGetTokenCsReq:
{
if (state != SessionState.WAITING_FOR_TOKEN)
{
@@ -193,7 +201,7 @@ public partial class Connection
}
goto default;
}
- case CmdId.PlayerLoginCsReq:
+ case CmdIds.PlayerLoginCsReq:
{
if (state != SessionState.WAITING_FOR_LOGIN)
{
@@ -204,15 +212,14 @@ public partial class Connection
default:
break;
}
- handler.OnHandle(header, payload);
+ handler.OnHandle(this, header, payload);
return true;
}
return false;
}
-
- public async Task SendPacketAsync(BasePacket packet)
+ public void SendPacket(BasePacket packet)
{
// Test
if (packet.CmdId <= 0)
@@ -226,10 +233,40 @@ public partial class Connection
{
return;
}
-
+#if DEBUG
+ LogPacket("Send", packet.CmdId, packet.Data);
+#endif
// Header
byte[] packetBytes = packet.BuildPacket();
- await Conversation.SendAsync(packetBytes, CancelToken.Token);
+#pragma warning disable CA2012
+ _ = Conversation.SendAsync(packetBytes, CancelToken.Token);
+#pragma warning restore CA2012
+ }
+
+ public void SendPacket(int cmdId)
+ {
+ // Test
+ if (cmdId <= 0)
+ {
+ Logger.Debug("Tried to send packet with missing cmd id!");
+ return;
+ }
+
+ // DO NOT REMOVE (unless we find a way to validate code before sending to client which I don't think we can)
+ if (BANNED_PACKETS.Contains(cmdId))
+ {
+ return;
+ }
+#if DEBUG
+ LogPacket("Send", (ushort)cmdId, []);
+#endif
+
+ // Header
+ byte[] packetBytes = new BasePacket((ushort)cmdId).BuildPacket();
+
+#pragma warning disable CA2012
+ _ = Conversation.SendAsync(packetBytes, CancelToken.Token);
+#pragma warning restore CA2012
}
}
diff --git a/GameServer/Server/GameSession.cs b/GameServer/Server/GameSession.cs
deleted file mode 100644
index 25bb3b47..00000000
--- a/GameServer/Server/GameSession.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace EggLink.DanhengServer.Server
-{
- public class GameSession()
- {
- }
-}
diff --git a/GameServer/Server/Packet/BasePacket.cs b/GameServer/Server/Packet/BasePacket.cs
index 474f778d..95d33902 100644
--- a/GameServer/Server/Packet/BasePacket.cs
+++ b/GameServer/Server/Packet/BasePacket.cs
@@ -1,4 +1,6 @@
-using System;
+using EggLink.DanhengServer.Util;
+using Google.Protobuf;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -6,13 +8,42 @@ using System.Threading.Tasks;
namespace EggLink.DanhengServer.Server.Packet
{
- public class BasePacket
+ public class BasePacket(ushort cmdId)
{
- public int CmdId;
+ private const uint HEADER_CONST = 0x9d74c714;
+ private const uint TAIL_CONST = 0xd7a152c8;
+
+ public ushort CmdId { get; set; } = cmdId;
+ public byte[] Data { get; private set; } = [];
+
+ public void SetData(byte[] data)
+ {
+ Data = data;
+ }
+
+ public void SetData(IMessage message)
+ {
+ Data = message.ToByteArray();
+ }
public byte[] BuildPacket()
{
- return [];
+ using MemoryStream? ms = new();
+ using BinaryWriter? bw = new(ms);
+
+ bw.WriteUInt32BE(HEADER_CONST);
+ bw.WriteUInt16BE(CmdId);
+ bw.WriteUInt16BE(0);
+ bw.WriteUInt32BE((uint)Data.Length);
+ if (Data.Length > 0)
+ {
+ bw.Write(Data);
+ }
+ bw.WriteUInt32BE(TAIL_CONST);
+
+ byte[] packet = ms.ToArray();
+
+ return packet;
}
}
}
diff --git a/GameServer/Server/Packet/CmdId.cs b/GameServer/Server/Packet/CmdIds.cs
similarity index 99%
rename from GameServer/Server/Packet/CmdId.cs
rename to GameServer/Server/Packet/CmdIds.cs
index 5431078e..427ff3f9 100644
--- a/GameServer/Server/Packet/CmdId.cs
+++ b/GameServer/Server/Packet/CmdIds.cs
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace EggLink.DanhengServer.Server.Packet
{
- public class CmdId
+ public class CmdIds
{
// None
public const int None = 0;
diff --git a/GameServer/Server/Packet/Handler.cs b/GameServer/Server/Packet/Handler.cs
index 3d1358eb..301718ab 100644
--- a/GameServer/Server/Packet/Handler.cs
+++ b/GameServer/Server/Packet/Handler.cs
@@ -1,13 +1,7 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace EggLink.DanhengServer.Server.Packet
+namespace EggLink.DanhengServer.Server.Packet
{
public abstract class Handler
{
- public abstract void OnHandle(byte[] header, byte[] data);
+ public abstract void OnHandle(Connection connection, byte[] header, byte[] data);
}
}
diff --git a/GameServer/Server/Packet/HandlerManager.cs b/GameServer/Server/Packet/HandlerManager.cs
index 8e10f5a9..1863f786 100644
--- a/GameServer/Server/Packet/HandlerManager.cs
+++ b/GameServer/Server/Packet/HandlerManager.cs
@@ -1,10 +1,4 @@
-using EggLink.DanhengServer.Data;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
+using System.Reflection;
namespace EggLink.DanhengServer.Server.Packet
{
diff --git a/GameServer/Server/Packet/Recv/Avatar/HandlerGetAvatarDataCsReq.cs b/GameServer/Server/Packet/Recv/Avatar/HandlerGetAvatarDataCsReq.cs
new file mode 100644
index 00000000..b4718287
--- /dev/null
+++ b/GameServer/Server/Packet/Recv/Avatar/HandlerGetAvatarDataCsReq.cs
@@ -0,0 +1,13 @@
+using EggLink.DanhengServer.Server.Packet.Send.Avatar;
+
+namespace EggLink.DanhengServer.Server.Packet.Recv.Avatar
+{
+ [Opcode(CmdIds.GetAvatarDataCsReq)]
+ public class HandlerGetAvatarDataCsReq : Handler
+ {
+ public override void OnHandle(Connection connection, byte[] header, byte[] data)
+ {
+ connection.SendPacket(new PacketGetAvatarDataScRsp(connection.Player!));
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Recv/Mission/HandlerGetMissionStatusCsReq.cs b/GameServer/Server/Packet/Recv/Mission/HandlerGetMissionStatusCsReq.cs
new file mode 100644
index 00000000..2e4d3471
--- /dev/null
+++ b/GameServer/Server/Packet/Recv/Mission/HandlerGetMissionStatusCsReq.cs
@@ -0,0 +1,18 @@
+using EggLink.DanhengServer.Proto;
+using EggLink.DanhengServer.Server.Packet.Send.Mission;
+
+namespace EggLink.DanhengServer.Server.Packet.Recv.Mission
+{
+ [Opcode(CmdIds.GetMissionStatusCsReq)]
+ public class HandlerGetMissionStatusCsReq : Handler
+ {
+ public override void OnHandle(Connection connection, byte[] header, byte[] data)
+ {
+ var req = GetMissionStatusCsReq.Parser.ParseFrom(data);
+ if (req != null)
+ {
+ connection.SendPacket(new PacketGetMissionStatusScRsp(req));
+ }
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Recv/Player/HandlerGetBagCsReq.cs b/GameServer/Server/Packet/Recv/Player/HandlerGetBagCsReq.cs
new file mode 100644
index 00000000..d0fbdb61
--- /dev/null
+++ b/GameServer/Server/Packet/Recv/Player/HandlerGetBagCsReq.cs
@@ -0,0 +1,18 @@
+using EggLink.DanhengServer.Server.Packet.Send.Player;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Server.Packet.Recv.Player
+{
+ [Opcode(CmdIds.GetBagCsReq)]
+ public class HandlerGetBagCsReq : Handler
+ {
+ public override void OnHandle(Connection connection, byte[] header, byte[] data)
+ {
+ connection.SendPacket(new PacketGetBagScRsp(connection.Player!));
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Recv/Player/HandlerGetBasicInfoCsReq.cs b/GameServer/Server/Packet/Recv/Player/HandlerGetBasicInfoCsReq.cs
new file mode 100644
index 00000000..673a057c
--- /dev/null
+++ b/GameServer/Server/Packet/Recv/Player/HandlerGetBasicInfoCsReq.cs
@@ -0,0 +1,18 @@
+using EggLink.DanhengServer.Server.Packet.Send.Player;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Server.Packet.Recv.Player
+{
+ [Opcode(CmdIds.GetBasicInfoCsReq)]
+ public class HandlerGetBasicInfoCsReq : Handler
+ {
+ public override void OnHandle(Connection connection, byte[] header, byte[] data)
+ {
+ connection.SendPacket(new PacketGetBasicInfoScRsp(connection.Player!));
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Recv/Player/HandlerGetHeroBasicTypeInfoCsReq.cs b/GameServer/Server/Packet/Recv/Player/HandlerGetHeroBasicTypeInfoCsReq.cs
new file mode 100644
index 00000000..ce925790
--- /dev/null
+++ b/GameServer/Server/Packet/Recv/Player/HandlerGetHeroBasicTypeInfoCsReq.cs
@@ -0,0 +1,13 @@
+using EggLink.DanhengServer.Server.Packet.Send.Player;
+
+namespace EggLink.DanhengServer.Server.Packet.Recv.Player
+{
+ [Opcode(CmdIds.GetHeroBasicTypeInfoCsReq)]
+ public class HandlerGetHeroBasicTypeInfoCsReq : Handler
+ {
+ public override void OnHandle(Connection connection, byte[] header, byte[] data)
+ {
+ connection.SendPacket(new PacketGetHeroBasicTypeInfoScRsp(connection.Player!));
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Recv/Player/HandlerGetPlayerBoardDataCsReq.cs b/GameServer/Server/Packet/Recv/Player/HandlerGetPlayerBoardDataCsReq.cs
new file mode 100644
index 00000000..82e88421
--- /dev/null
+++ b/GameServer/Server/Packet/Recv/Player/HandlerGetPlayerBoardDataCsReq.cs
@@ -0,0 +1,13 @@
+using EggLink.DanhengServer.Server.Packet.Send.Player;
+
+namespace EggLink.DanhengServer.Server.Packet.Recv.Player
+{
+ [Opcode(CmdIds.GetPlayerBoardDataCsReq)]
+ public class HandlerGetPlayerBoardDataCsReq : Handler
+ {
+ public override void OnHandle(Connection connection, byte[] header, byte[] data)
+ {
+ connection.SendPacket(new PacketGetPlayerBoardDataScRsp(connection.Player!));
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Recv/Player/HandlerPlayerGetTokenCsReq.cs b/GameServer/Server/Packet/Recv/Player/HandlerPlayerGetTokenCsReq.cs
index 15ccb9cd..5a1c1cd4 100644
--- a/GameServer/Server/Packet/Recv/Player/HandlerPlayerGetTokenCsReq.cs
+++ b/GameServer/Server/Packet/Recv/Player/HandlerPlayerGetTokenCsReq.cs
@@ -1,20 +1,33 @@
-using EggLink.DanhengServer.Proto;
+using EggLink.DanhengServer.Common.Enums;
+using EggLink.DanhengServer.Database;
+using EggLink.DanhengServer.Database.Player;
+using EggLink.DanhengServer.Game.Player;
+using EggLink.DanhengServer.Proto;
+using EggLink.DanhengServer.Server.Packet.Send.Player;
using EggLink.DanhengServer.Util;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace EggLink.DanhengServer.Server.Packet.Recv.Player
{
- [Opcode(CmdId.PlayerGetTokenCsReq)]
+ [Opcode(CmdIds.PlayerGetTokenCsReq)]
public class HandlerPlayerGetTokenCsReq : Handler
{
- public override void OnHandle(byte[] header, byte[] data)
+ public override void OnHandle(Connection connection, byte[] header, byte[] data)
{
var req = PlayerGetTokenCsReq.Parser.ParseFrom(data);
- Logger.GetByClassName().Debug("OnHandle" + req.ToString());
+ connection.State = SessionState.WAITING_FOR_LOGIN;
+ var pd = DatabaseHelper.Instance?.GetInstance(long.Parse(req.AccountUid));
+ if (pd == null)
+ connection.Player = new PlayerInstance()
+ {
+ Uid = ushort.Parse(req.AccountUid),
+ };
+ else
+ {
+ connection.Player = new PlayerInstance(pd);
+ }
+ connection.Player.OnLogin();
+ connection.Player.Connection = connection;
+ connection.SendPacket(new PacketPlayerGetTokenScRsp(connection));
}
}
}
diff --git a/GameServer/Server/Packet/Recv/Player/HandlerPlayerHeartBeatCsReq.cs b/GameServer/Server/Packet/Recv/Player/HandlerPlayerHeartBeatCsReq.cs
new file mode 100644
index 00000000..9a5cef68
--- /dev/null
+++ b/GameServer/Server/Packet/Recv/Player/HandlerPlayerHeartBeatCsReq.cs
@@ -0,0 +1,23 @@
+using EggLink.DanhengServer.Proto;
+using EggLink.DanhengServer.Server.Packet.Send.Player;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Server.Packet.Recv.Player
+{
+ [Opcode(CmdIds.PlayerHeartBeatCsReq)]
+ public class HandlerPlayerHeartBeatCsReq : Handler
+ {
+ public override void OnHandle(Connection connection, byte[] header, byte[] data)
+ {
+ var req = PlayerHeartbeatCsReq.Parser.ParseFrom(data);
+ if (req != null)
+ {
+ connection.SendPacket(new PacketPlayerHeartBeatScRsp((long)req.ClientTimeMs));
+ }
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Recv/Player/HandlerPlayerLoginCsReq.cs b/GameServer/Server/Packet/Recv/Player/HandlerPlayerLoginCsReq.cs
new file mode 100644
index 00000000..e5248f24
--- /dev/null
+++ b/GameServer/Server/Packet/Recv/Player/HandlerPlayerLoginCsReq.cs
@@ -0,0 +1,15 @@
+using EggLink.DanhengServer.Common.Enums;
+using EggLink.DanhengServer.Server.Packet.Send.Player;
+
+namespace EggLink.DanhengServer.Server.Packet.Recv.Player
+{
+ [Opcode(CmdIds.PlayerLoginCsReq)]
+ public class HandlerPlayerLoginCsReq : Handler
+ {
+ public override void OnHandle(Connection connection, byte[] header, byte[] data)
+ {
+ connection.State = SessionState.ACTIVE;
+ connection.SendPacket(new PacketPlayerLoginScRsp(connection));
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Recv/Player/HandlerPlayerLoginFinishCsReq.cs b/GameServer/Server/Packet/Recv/Player/HandlerPlayerLoginFinishCsReq.cs
new file mode 100644
index 00000000..92627212
--- /dev/null
+++ b/GameServer/Server/Packet/Recv/Player/HandlerPlayerLoginFinishCsReq.cs
@@ -0,0 +1,12 @@
+namespace EggLink.DanhengServer.Server.Packet.Recv.Player
+{
+ [Opcode(CmdIds.PlayerLoginFinishCsReq)]
+ public class HandlerPlayerLoginFinishCsReq : Handler
+ {
+ public override void OnHandle(Connection connection, byte[] header, byte[] data)
+ {
+ connection.SendPacket(CmdIds.PlayerLoginFinishScRsp);
+ connection.SendPacket(CmdIds.GetArchiveDataScRsp);
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Recv/Scene/HandlerGetEnteredSceneCsReq.cs b/GameServer/Server/Packet/Recv/Scene/HandlerGetEnteredSceneCsReq.cs
new file mode 100644
index 00000000..ca3bdae3
--- /dev/null
+++ b/GameServer/Server/Packet/Recv/Scene/HandlerGetEnteredSceneCsReq.cs
@@ -0,0 +1,13 @@
+using EggLink.DanhengServer.Server.Packet.Send.Scene;
+
+namespace EggLink.DanhengServer.Server.Packet.Recv.Scene
+{
+ [Opcode(CmdIds.GetEnteredSceneCsReq)]
+ public class HandlerGetEnteredSceneCsReq : Handler
+ {
+ public override void OnHandle(Connection connection, byte[] header, byte[] data)
+ {
+ connection.SendPacket(new PacketGetEnteredSceneScRsp());
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Avatar/PacketGetAvatarDataScRsp.cs b/GameServer/Server/Packet/Send/Avatar/PacketGetAvatarDataScRsp.cs
new file mode 100644
index 00000000..1c0bc791
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Avatar/PacketGetAvatarDataScRsp.cs
@@ -0,0 +1,23 @@
+using EggLink.DanhengServer.Game.Player;
+using EggLink.DanhengServer.Proto;
+
+namespace EggLink.DanhengServer.Server.Packet.Send.Avatar
+{
+ public class PacketGetAvatarDataScRsp : BasePacket
+ {
+ public PacketGetAvatarDataScRsp(PlayerInstance player) : base(CmdIds.GetAvatarDataScRsp)
+ {
+ var proto = new GetAvatarDataScRsp()
+ {
+ IsGetAll = true,
+ };
+
+ player.AvatarManager?.AvatarData?.Avatars?.ForEach(avatar =>
+ {
+ proto.AvatarList.Add(avatar.ToProto());
+ });
+
+ SetData(proto);
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Mission/PacketGetMissionStatusScRsp.cs b/GameServer/Server/Packet/Send/Mission/PacketGetMissionStatusScRsp.cs
new file mode 100644
index 00000000..97764c1a
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Mission/PacketGetMissionStatusScRsp.cs
@@ -0,0 +1,28 @@
+using EggLink.DanhengServer.Proto;
+
+namespace EggLink.DanhengServer.Server.Packet.Send.Mission
+{
+ public class PacketGetMissionStatusScRsp : BasePacket
+ {
+ public PacketGetMissionStatusScRsp(GetMissionStatusCsReq req) : base(CmdIds.GetMissionStatusScRsp)
+ {
+ var proto = new GetMissionStatusScRsp();
+
+ foreach (var item in req.MainMissionIdList)
+ {
+ proto.FinishedMainMissionIdList.Add(item);
+ }
+
+ foreach (var item in req.SubMissionIdList)
+ {
+ proto.SubMissionStatusList.Add(new Proto.Mission()
+ {
+ Id = item,
+ Status = MissionStatus.MissionFinish,
+ });
+ }
+
+ SetData(proto);
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Player/PacketGetBagScRsp.cs b/GameServer/Server/Packet/Send/Player/PacketGetBagScRsp.cs
new file mode 100644
index 00000000..ebbdb615
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Player/PacketGetBagScRsp.cs
@@ -0,0 +1,30 @@
+using EggLink.DanhengServer.Game.Player;
+using EggLink.DanhengServer.Proto;
+
+namespace EggLink.DanhengServer.Server.Packet.Send.Player
+{
+ public class PacketGetBagScRsp : BasePacket
+ {
+ public PacketGetBagScRsp(PlayerInstance player) : base(CmdIds.GetBagScRsp)
+ {
+ var proto = new GetBagScRsp();
+
+ player.InventoryManager.Data.MaterialItems.ForEach(item =>
+ {
+ proto.MaterialList.Add(item.ToMaterialProto());
+ });
+
+ player.InventoryManager.Data.RelicItems.ForEach(item =>
+ {
+ proto.RelicList.Add(item.ToRelicProto());
+ });
+
+ player.InventoryManager.Data.EquipmentItems.ForEach(item =>
+ {
+ proto.EquipmentList.Add(item.ToEquipmentProto());
+ });
+
+ SetData(proto);
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Player/PacketGetBasicInfoScRsp.cs b/GameServer/Server/Packet/Send/Player/PacketGetBasicInfoScRsp.cs
new file mode 100644
index 00000000..927f4bfa
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Player/PacketGetBasicInfoScRsp.cs
@@ -0,0 +1,26 @@
+using EggLink.DanhengServer.Game.Player;
+using EggLink.DanhengServer.Proto;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Server.Packet.Send.Player
+{
+ public class PacketGetBasicInfoScRsp : BasePacket
+ {
+ public PacketGetBasicInfoScRsp(PlayerInstance player) : base(CmdIds.GetBasicInfoScRsp)
+ {
+ var proto = new GetBasicInfoScRsp()
+ {
+ CurDay = 1,
+ NextRecoverTime = player.Data.NextStaminaRecover / 1000,
+ GameplayBirthday = (uint)player.Data.Birthday,
+ PlayerSettingInfo = new(),
+ };
+
+ SetData(proto);
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Player/PacketGetHeroBasicTypeInfoScRsp.cs b/GameServer/Server/Packet/Send/Player/PacketGetHeroBasicTypeInfoScRsp.cs
new file mode 100644
index 00000000..d760ed1b
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Player/PacketGetHeroBasicTypeInfoScRsp.cs
@@ -0,0 +1,19 @@
+using EggLink.DanhengServer.Game.Player;
+using EggLink.DanhengServer.Proto;
+
+namespace EggLink.DanhengServer.Server.Packet.Send.Player
+{
+ public class PacketGetHeroBasicTypeInfoScRsp : BasePacket
+ {
+ public PacketGetHeroBasicTypeInfoScRsp(PlayerInstance player) : base(CmdIds.GetHeroBasicTypeInfoScRsp)
+ {
+ var proto = new GetHeroBasicTypeInfoScRsp()
+ {
+ Gender = player.Data.CurrentGender ?? Gender.None,
+ CurBasicType = (HeroBasicType)player.Data.CurBasicType,
+ };
+
+ SetData(proto);
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Player/PacketGetPlayerBoardDataScRsp.cs b/GameServer/Server/Packet/Send/Player/PacketGetPlayerBoardDataScRsp.cs
new file mode 100644
index 00000000..88f34c00
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Player/PacketGetPlayerBoardDataScRsp.cs
@@ -0,0 +1,37 @@
+using EggLink.DanhengServer.Game.Player;
+using EggLink.DanhengServer.Proto;
+
+namespace EggLink.DanhengServer.Server.Packet.Send.Player
+{
+ public class PacketGetPlayerBoardDataScRsp : BasePacket
+ {
+ public PacketGetPlayerBoardDataScRsp(PlayerInstance player) : base(CmdIds.GetPlayerBoardDataScRsp)
+ {
+ var proto = new GetPlayerBoardDataScRsp()
+ {
+ CurrentHeadIconId = (uint)player.Data.HeadIcon,
+ Signature = player.Data.Signature,
+ };
+
+ player.PlayerUnlockData.HeadIcons.ForEach(id =>
+ {
+ HeadIcon headIcon = new() { Id = (uint)id };
+ proto.UnlockedHeadIconList.Add(headIcon);
+ });
+
+ proto.DisplayAvatarVec = new();
+ var pos = 0;
+ player.AvatarManager.AvatarData.DisplayAvatars.ForEach(avatar =>
+ {
+ DisplayAvatar displayAvatar = new()
+ {
+ AvatarId = (uint)avatar,
+ Pos = (uint)pos++,
+ };
+ proto.DisplayAvatarVec.DisplayAvatarList.Add(displayAvatar);
+ });
+
+ SetData(proto);
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Player/PacketPlayerGetTokenScRsp.cs b/GameServer/Server/Packet/Send/Player/PacketPlayerGetTokenScRsp.cs
new file mode 100644
index 00000000..ed5dc285
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Player/PacketPlayerGetTokenScRsp.cs
@@ -0,0 +1,18 @@
+using EggLink.DanhengServer.Proto;
+
+namespace EggLink.DanhengServer.Server.Packet.Send.Player
+{
+ public class PacketPlayerGetTokenScRsp : BasePacket
+ {
+ public PacketPlayerGetTokenScRsp(Connection connection) : base(CmdIds.PlayerGetTokenScRsp)
+ {
+ var rsp = new PlayerGetTokenScRsp()
+ {
+ BlackInfo = new BlackInfo(),
+ Uid = connection.Player?.Uid ?? 0,
+ };
+
+ SetData(rsp);
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Player/PacketPlayerHeartBeatScRsp.cs b/GameServer/Server/Packet/Send/Player/PacketPlayerHeartBeatScRsp.cs
new file mode 100644
index 00000000..12e44325
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Player/PacketPlayerHeartBeatScRsp.cs
@@ -0,0 +1,23 @@
+using EggLink.DanhengServer.Proto;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Server.Packet.Send.Player
+{
+ public class PacketPlayerHeartBeatScRsp : BasePacket
+ {
+ public PacketPlayerHeartBeatScRsp(long clientTime) : base(CmdIds.PlayerHeartBeatScRsp)
+ {
+ var data = new PlayerHeartbeatScRsp()
+ {
+ ClientTimeMs = (ulong)clientTime,
+ ServerTimeMs = (ulong)(DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond),
+ };
+
+ SetData(data);
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Player/PacketPlayerLoginScRsp.cs b/GameServer/Server/Packet/Send/Player/PacketPlayerLoginScRsp.cs
new file mode 100644
index 00000000..ea26b99d
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Player/PacketPlayerLoginScRsp.cs
@@ -0,0 +1,26 @@
+using EggLink.DanhengServer.Proto;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Policy;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Server.Packet.Send.Player
+{
+ public class PacketPlayerLoginScRsp : BasePacket
+ {
+ public PacketPlayerLoginScRsp(Connection connection) : base(CmdIds.PlayerLoginScRsp)
+ {
+ var rsp = new PlayerLoginScRsp()
+ {
+ CurTimezone = (int)TimeZoneInfo.Local.BaseUtcOffset.TotalHours,
+ ServerTimestampMs = (ulong)(DateTime.Now.Ticks / 10000),
+ BasicInfo = connection?.Player?.ToProto(), // should not be null
+ Stamina = (uint)(connection?.Player?.Data.Stamina ?? 0),
+ };
+
+ SetData(rsp);
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Player/PacketPlayerSyncScNotify.cs b/GameServer/Server/Packet/Send/Player/PacketPlayerSyncScNotify.cs
new file mode 100644
index 00000000..01b879bb
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Player/PacketPlayerSyncScNotify.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EggLink.DanhengServer.Server.Packet.Send.Player
+{
+ public class PacketPlayerSyncScNotify : BasePacket
+ {
+ public PacketPlayerSyncScNotify() : base(CmdIds.PlayerSyncScNotify)
+ {
+
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Player/PacketStaminaInfoScNotify.cs b/GameServer/Server/Packet/Send/Player/PacketStaminaInfoScNotify.cs
new file mode 100644
index 00000000..809a7575
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Player/PacketStaminaInfoScNotify.cs
@@ -0,0 +1,20 @@
+using EggLink.DanhengServer.Game.Player;
+using EggLink.DanhengServer.Proto;
+
+namespace EggLink.DanhengServer.Server.Packet.Send.Player
+{
+ public class PacketStaminaInfoScNotify : BasePacket
+ {
+ public PacketStaminaInfoScNotify(PlayerInstance player) : base(CmdIds.StaminaInfoScNotify)
+ {
+ var proto = new StaminaInfoScNotify()
+ {
+ Stamina = (uint)player.Data.Stamina,
+ ReserveStamina = (uint)player.Data.StaminaReserve,
+ NextRecoverTime = player.Data.NextStaminaRecover,
+ };
+
+ SetData(proto);
+ }
+ }
+}
diff --git a/GameServer/Server/Packet/Send/Scene/PacketGetEnteredSceneScRsp.cs b/GameServer/Server/Packet/Send/Scene/PacketGetEnteredSceneScRsp.cs
new file mode 100644
index 00000000..142274bc
--- /dev/null
+++ b/GameServer/Server/Packet/Send/Scene/PacketGetEnteredSceneScRsp.cs
@@ -0,0 +1,33 @@
+using EggLink.DanhengServer.Data;
+using EggLink.DanhengServer.Proto;
+
+namespace EggLink.DanhengServer.Server.Packet.Send.Scene
+{
+ public class PacketGetEnteredSceneScRsp : BasePacket
+ {
+ public PacketGetEnteredSceneScRsp() : base(CmdIds.GetEnteredSceneScRsp)
+ {
+ var proto = new GetEnteredSceneScRsp();
+
+ foreach (var excel in GameData.MapEntranceData.Values)
+ {
+ // Skip these
+ if (excel.FinishMainMissionList.Count == 0 && excel.FinishMainMissionList.Count == 0)
+ {
+ continue;
+ }
+
+ // Add info
+ var info = new EnteredSceneInfo()
+ {
+ FloorId = (uint)excel.FloorID,
+ PlaneId = (uint)excel.PlaneID,
+ };
+
+ proto.EnteredSceneInfo.Add(info);
+ }
+
+ SetData(proto);
+ }
+ }
+}
diff --git a/WebServer/Handler/ComboTokenGranterHandler.cs b/WebServer/Handler/ComboTokenGranterHandler.cs
index 0e4ddfec..f52ac559 100644
--- a/WebServer/Handler/ComboTokenGranterHandler.cs
+++ b/WebServer/Handler/ComboTokenGranterHandler.cs
@@ -17,7 +17,7 @@ namespace EggLink.DanhengServer.WebServer.Handler
res.message = "Invalid login data";
return new JsonResult(res);
}
- AccountData? account = AccountData.GetAccountByUid(long.Parse(tokenData.uid)) as AccountData;
+ AccountData? account = AccountData.GetAccountByUid(long.Parse(tokenData.uid));
if (account == null)
{
res.retcode = -201;
diff --git a/WebServer/Handler/TokenLoginHandler.cs b/WebServer/Handler/TokenLoginHandler.cs
index 842dc90b..71344dcf 100644
--- a/WebServer/Handler/TokenLoginHandler.cs
+++ b/WebServer/Handler/TokenLoginHandler.cs
@@ -9,7 +9,7 @@ namespace EggLink.DanhengServer.WebServer.Handler
{
public JsonResult Handle(string uid, string token)
{
- AccountData? account = AccountData.GetAccountByUid(long.Parse(uid)) as AccountData;
+ AccountData? account = AccountData.GetAccountByUid(long.Parse(uid));
var res = new LoginResJson();
if (account == null || !account.DispatchToken.Equals(token))
{
diff --git a/WebServer/Handler/UsernameLoginHandler.cs b/WebServer/Handler/UsernameLoginHandler.cs
index 0de9cb3b..32f11b31 100644
--- a/WebServer/Handler/UsernameLoginHandler.cs
+++ b/WebServer/Handler/UsernameLoginHandler.cs
@@ -11,14 +11,14 @@ namespace EggLink.DanhengServer.WebServer.Handler
public JsonResult Handle(string account, string password, bool isCrypto)
{
LoginResJson res = new();
- AccountData accountData = (AccountData)AccountData.GetAccountByUserName(account);
+ AccountData? accountData = AccountData.GetAccountByUserName(account);
if (accountData == null)
{
if (ConfigManager.Config.ServerOption.AutoCreateUser)
{
AccountHelper.CreateAccount(account, 0);
- accountData = (AccountData)AccountData.GetAccountByUserName(account);
+ accountData = AccountData.GetAccountByUserName(account);
}
else
{
diff --git a/WebServer/WebServer.csproj b/WebServer/WebServer.csproj
index 50bf9dc4..d84feb49 100644
--- a/WebServer/WebServer.csproj
+++ b/WebServer/WebServer.csproj
@@ -14,6 +14,7 @@
+